Commit 86ae3b2a authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.12pre9

parent 6ae9dd08
......@@ -11921,7 +11921,7 @@ USB hub support
CONFIG_USB_HUB
To expand beyond the USB ports on the computer, a device called a
hub is used. This driver supports hubs, allowing them to be used.
Say 'Y'
Say 'Y'.
USB mouse support
CONFIG_USB_MOUSE
......@@ -11931,7 +11931,7 @@ CONFIG_USB_MOUSE
USB keyboard support
CONFIG_USB_KBD
This driver allows usb keyboards to work under the USB stack.
This driver allows USB keyboards to work under the USB stack.
USB audio parsing support (Preliminary)
CONFIG_USB_AUDIO
......@@ -11943,6 +11943,13 @@ CONFIG_USB_ACM
This driver allows for devices which support the Abstract Control Model,
including many USB-based modems, ISDN adapters, and network adapters.
USB /proc filesystem entry support (Preliminary)
CONFIG_USB_PROC
This reports USB drivers and devices in the /proc filesystem.
Entries are located in /proc/bus/usb.
Note that you must enable support for the proc filesystem
for this to work.
Support for user-space parallel port device drivers
CONFIG_PPDEV
Saying Y to this adds support for /dev/parport device nodes. This
......
/proc/bus/usb filesystem output
===============================
(version 19990722)
The /proc filesystem for USB devices generates
/proc/bus/usb/drivers and /proc/bus/usb/devices.
/proc/bus/usb/drivers just lists the registered drivers,
one per line. Not very interesting or pretty.
In /proc/bus/usb/devices, each device's output has multiple
lines (except for a root hub) of ASCII output.
I made it ASCII instead of binary on purpose, so that someone
can obtain some useful data from it without the use of an
auxiliary program. However, with an auxiliary program, the numbers
in the first 4 columns of each "T:" line (topology info:
Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
(I think. I haven't proved this, but I have tested it with 3
different topo/connections and it looked possible.)
Each line is tagged with a one-character ID for that line:
T = Topology (etc.)
D = Device descriptor info.
P = Product ID info. (from Device descriptor, but they won't fit
together on one line)
C = Configuration descriptor info. (* = active configuration)
I = Interface descriptor info.
E = Endpoint descriptor info.
=======================================================================
/proc/bus/usb/devices output format:
Legend:
d = decimal number (may have leading spaces or 0's)
x = hexadecimal number (may have leading spaces or 0's)
s = string
Topology info:
T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s
| | | | | | | | | |__DriverName
| | | | | | | | |__MaxChildren
| | | | | | | |__Configured InterfaceNumber
| | | | | | |__Device Speed in Mbps
| | | | | |__DeviceNumber
| | | | |__Count of devices at this level
| | | |__Connector/Port on Parent for this device
| | |__Parent DeviceNumber
| |__Level in topology
|__Topology info tag
Device descriptor info & Product ID info:
D: Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
where
D: Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
| | | | | | |__NumberConfigurations
| | | | | |__MaxPacketSize of Default Endpoint
| | | | |__DeviceProtocol
| | | |__DeviceSubClass
| | |__DeviceClass
| |__Device USB version
|__Device info tag #1
where
P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
| | | |__Product revision number
| | |__Product ID code
| |__Vendor ID code
|__Device info tag #2
Configuration descriptor info:
C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
| | | | |__MaxPower in mA
| | | |__Attributes
| | |__ConfiguratioNumber
| |__NumberOfInterfaces
|__Config info tag
Interface descriptor info (can be multiple per Config):
I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx
| | | | | | |__InterfaceProtocol
| | | | | |__InterfaceSubClass
| | | | |__InterfaceClass
| | | |__NumberOfEndpoints
| | |__AlternateSettingNumber
| |__InterfaceNumber
|__Interface info tag
Endpoint descriptor info (can be multiple per Interface):
E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
| | | | |__Interval
| | | |__EndpointMaxPacketSize
| | |__Attributes(EndpointType)
| |__EndpointAddress(I=In,O=Out)
|__Endpoint info tag
=======================================================================
If a user or script is interested only in Topology info, for
example, use something like "grep ^T: /proc/bus/usb/devices"
for only the Topology lines. A command like
"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list
only the lines that begin with the characters in square brackets,
where the valid characters are TDPCIE. With a slightly more able
script, it can display any selected lines (for example, only T, D,
and P lines) and change their output format. (The "procusb"
Perl script is the beginning of this idea. It will list only
selected lines [selected from TDPCIE] or "All" lines from
/proc/bus/usb/devices.)
The Topology lines can be used to generate a graphic/pictorial
of the USB devices on a system's root hub. (See more below
on how to do this.)
The Configuration lines could be used to list maximum power
(in milliamps) that a system's USB devices are using.
For example, "grep ^C: /proc/bus/usb/devices".
Here's an example, from a system which has a UHCI root hub,
an external hub connected to the root hub, and a mouse and
a video camera connected to the external hub. [The video
camera is listed as (none) since it is not recognized by
any driver.]
T: Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= -1 Spd=12 If#= 0 MxCh= 2 Driver=(root hub)
T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 If#= 0 MxCh= 4 Driver=hub
D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0451 ProdID=1446 Rev= 1.00
C:* #If= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
I: If#= 0 Alt= 0 #EP= 1 Cls=09(hub ) Sub=00 Prot=00
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms
T: Lev=02 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=1.5 If#= 0 MxCh= 0 Driver=mouse
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0458 ProdID=0001 Rev= 0.00
C:* #If= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
I: If#= 0 Alt= 0 #EP= 1 Cls=03(HID ) Sub=01 Prot=02
E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms
T: Lev=02 Prnt=01 Port=02 Cnt=02 Dev#= 4 Spd=12 If#= 0 MxCh= 0 Driver=(none)
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=04c8 ProdID=0720 Rev= 1.01
C:* #If= 1 Cfg#= 1 Atr=80 MxPwr=500mA
I: If#= 0 Alt= 0 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms
E: Ad=82(I) Atr=01(Isoc) MxPS= 384 Ivl= 1ms
I: If#= 0 Alt= 1 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms
E: Ad=82(I) Atr=01(Isoc) MxPS= 240 Ivl= 1ms
I: If#= 0 Alt= 2 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms
E: Ad=82(I) Atr=01(Isoc) MxPS= 576 Ivl= 1ms
I: If#= 0 Alt= 3 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms
E: Ad=82(I) Atr=01(Isoc) MxPS= 464 Ivl= 1ms
I: If#= 0 Alt= 4 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms
E: Ad=82(I) Atr=01(Isoc) MxPS= 688 Ivl= 1ms
Selecting only the "T:" lines from this (for example, by using
"procusb t"), we have:
T: Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= -1 Spd=12 If#= 0 MxCh= 2 Driver=(root hub)
T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 If#= 0 MxCh= 4 Driver=hub
T: Lev=02 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=1.5 If#= 0 MxCh= 0 Driver=mouse
T: Lev=02 Prnt=01 Port=02 Cnt=02 Dev#= 4 Spd=12 If#= 0 MxCh= 0 Driver=(none)
Physically this looks like (or could be converted to):
+------------------+
| PC/root_hub (12)| Dev# = -1
+------------------+ (nn) is Mbps.
Level 0 | CN.0 | CN.1 | [CN = connector/port #]
+------------------+
/
/
+-----------------------+
Level 1 | Dev#1: 4-port hub (12)|
+-----------------------+
|CN.0 |CN.1 |CN.2 |CN.3 |
+-----------------------+
\ \____________________
\_____ \
\ \
+--------------------+ +--------------------+
Level 2 | Dev# 3: mouse (1.5)| | Dev# 4: (none) (12)|
+--------------------+ +--------------------+
Or, in a more tree-like structure (ports [Connectors] without
connections could be omitted):
PC: Dev# -1, root hub, 2 ports, 12 Mbps
|_ CN.0: Dev# 1, hub, 4 ports, 12 Mbps
|_ CN.0: Dev #3, mouse, 1.5 Mbps
|_ CN.1:
|_ CN.2: Dev #4, (none), 12 Mbps [or use "unknown" for (none)]
|_ CN.3:
|_ CN.1:
### END ###
......@@ -1143,11 +1143,3 @@ sys_call_table:
.quad sys_capget
.quad sys_capset
.quad sys_sendfile /* 370 */
.quad sys_timer_create
.quad sys_timer_settime
.quad sys_timer_gettime
.quad sys_timer_getoverrun
.quad sys_timer_delete /* 375 */
.quad sys_clock_gettime
.quad sys_clock_settime
.quad sys_clock_getres /* 378 */
......@@ -200,16 +200,8 @@
.long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_ni_syscall)
/* 190 */ .long SYMBOL_NAME(sys_vfork_wrapper)
.long SYMBOL_NAME(sys_timer_create)
.long SYMBOL_NAME(sys_timer_settime)
.long SYMBOL_NAME(sys_timer_gettime)
.long SYMBOL_NAME(sys_timer_getoverrun)
/* 195 */ .long SYMBOL_NAME(sys_timer_delete)
.long SYMBOL_NAME(sys_clock_gettime)
.long SYMBOL_NAME(sys_clock_settime)
.long SYMBOL_NAME(sys_clock_getres)
.rept NR_syscalls-198
.rept NR_syscalls-186
.long SYMBOL_NAME(sys_ni_syscall)
.endr
#endif
......@@ -560,14 +560,6 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
.long SYMBOL_NAME(sys_timer_create)
.long SYMBOL_NAME(sys_timer_settime)
.long SYMBOL_NAME(sys_timer_gettime)
.long SYMBOL_NAME(sys_timer_getoverrun)
.long SYMBOL_NAME(sys_timer_delete) /* 195 */
.long SYMBOL_NAME(sys_clock_gettime)
.long SYMBOL_NAME(sys_clock_settime)
.long SYMBOL_NAME(sys_clock_getres) /* 198 */
/*
* NOTE!! This doesn't have to be exact - we just have
......@@ -575,6 +567,6 @@ ENTRY(sys_call_table)
* entries. Don't panic if you notice that this hasn't
* been shrunk every time we add a new system call.
*/
.rept NR_syscalls-198
.rept NR_syscalls-190
.long SYMBOL_NAME(sys_ni_syscall)
.endr
......@@ -1384,12 +1384,6 @@ void __init smp_boot_cpus(void)
printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
SMP_PRINTK(("Boot done.\n"));
/*
* now we know the other CPUs have fired off and we know our
* APIC ID, so we can go init the TSS and stuff:
*/
cpu_init();
cache_APIC_registers();
#ifndef CONFIG_VISWS
/*
......@@ -1401,6 +1395,11 @@ void __init smp_boot_cpus(void)
#endif
smp_done:
/*
* now we know the other CPUs have fired off and we know our
* APIC ID, so we can go init the TSS and stuff:
*/
cpu_init();
}
......@@ -1580,7 +1579,7 @@ static inline void send_IPI_single(int dest, int vector)
* bad as in the early days of SMP, so we might ease some of the
* paranoia here.
*/
static void flush_tlb_others(void)
static void flush_tlb_others(unsigned int cpumask)
{
int cpu = smp_processor_id();
int stuck;
......@@ -1590,17 +1589,9 @@ static void flush_tlb_others(void)
* it's important that we do not generate any APIC traffic
* until the AP CPUs have booted up!
*/
if (cpu_online_map) {
/*
* The assignment is safe because it's volatile so the
* compiler cannot reorder it, because the i586 has
* strict memory ordering and because only the kernel
* lock holder may issue a tlb flush. If you break any
* one of those three change this to an atomic bus
* locked or.
*/
smp_invalidate_needed = cpu_online_map;
cpumask &= cpu_online_map;
if (cpumask) {
atomic_set_mask(cpumask, &smp_invalidate_needed);
/*
* Processors spinning on some lock with IRQs disabled
......@@ -1623,8 +1614,10 @@ static void flush_tlb_others(void)
/*
* Take care of "crossing" invalidates
*/
if (test_bit(cpu, &smp_invalidate_needed))
clear_bit(cpu, &smp_invalidate_needed);
if (test_bit(cpu, &smp_invalidate_needed)) {
clear_bit(cpu, &smp_invalidate_needed);
local_flush_tlb();
}
--stuck;
if (!stuck) {
printk("stuck on TLB IPI wait (CPU#%d)\n",cpu);
......@@ -1647,44 +1640,43 @@ void flush_tlb_current_task(void)
unsigned long vm_mask = 1 << current->processor;
struct mm_struct *mm = current->mm;
if (mm->cpu_vm_mask != vm_mask)
flush_tlb_others();
mm->cpu_vm_mask = vm_mask;
if (mm->cpu_vm_mask != vm_mask) {
flush_tlb_others(mm->cpu_vm_mask & ~vm_mask);
mm->cpu_vm_mask = vm_mask;
}
local_flush_tlb();
}
void flush_tlb_mm(struct mm_struct * mm)
{
unsigned long vm_mask = 1 << current->processor;
unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask;
if (mm->cpu_vm_mask & ~vm_mask)
flush_tlb_others();
mm->cpu_vm_mask = 0;
if (current->active_mm == mm) {
local_flush_tlb();
mm->cpu_vm_mask = vm_mask;
return;
local_flush_tlb();
}
mm->cpu_vm_mask = 0;
flush_tlb_others(cpu_mask);
}
void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
{
unsigned long vm_mask = 1 << current->processor;
struct mm_struct *mm = vma->vm_mm;
unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask;
if (mm->cpu_vm_mask & ~vm_mask)
flush_tlb_others();
mm->cpu_vm_mask = 0;
if (current->active_mm == mm) {
__flush_tlb_one(va);
mm->cpu_vm_mask = vm_mask;
return;
}
mm->cpu_vm_mask = 0;
flush_tlb_others(cpu_mask);
}
void flush_tlb_all(void)
{
flush_tlb_others();
flush_tlb_others(~(1 << current->processor));
local_flush_tlb();
}
......@@ -1908,13 +1900,24 @@ asmlinkage void smp_reschedule_interrupt(void)
}
/*
* Invalidate call-back
* Invalidate call-back.
*
* Mark the CPU as a VM user if there is a active
* thread holding on to an mm at this time. This
* allows us to optimize CPU cross-calls even in the
* presense of lazy TLB handling.
*/
asmlinkage void smp_invalidate_interrupt(void)
{
if (test_and_clear_bit(smp_processor_id(), &smp_invalidate_needed))
local_flush_tlb();
struct task_struct *tsk = current;
unsigned int cpu = tsk->processor;
if (test_and_clear_bit(cpu, &smp_invalidate_needed)) {
struct mm_struct *mm = tsk->mm;
if (mm)
atomic_set_mask(1 << cpu, &mm->cpu_vm_mask);
local_flush_tlb();
}
ack_APIC_irq();
}
......
......@@ -245,9 +245,6 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
printk(" at virtual address %08lx\n",address);
printk(" printing eip:\n");
printk("%08lx\n", regs->eip);
__asm__("movl %%cr3,%0" : "=r" (page));
printk(KERN_ALERT "current->active_mm.pgd = %p, %%cr3 = %08lx\n",
tsk->active_mm->pgd, page);
page = ((unsigned long *) __va(page))[address >> 22];
printk(KERN_ALERT "*pde = %08lx\n", page);
if (page & 1) {
......
......@@ -609,14 +609,6 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
.long SYMBOL_NAME(sys_timer_create)
.long SYMBOL_NAME(sys_timer_settime)
.long SYMBOL_NAME(sys_timer_gettime)
.long SYMBOL_NAME(sys_timer_getoverrun)
.long SYMBOL_NAME(sys_timer_delete) /* 195 */
.long SYMBOL_NAME(sys_clock_gettime)
.long SYMBOL_NAME(sys_clock_settime)
.long SYMBOL_NAME(sys_clock_getres) /* 198 */
.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
.long SYMBOL_NAME(sys_ni_syscall)
......
......@@ -225,11 +225,3 @@ SYS(sys_sigaltstack, 2)
SYS(sys_sendfile, 3)
SYS(sys_ni_syscall, 0)
SYS(sys_ni_syscall, 0)
SYS(sys_timer_create, 3) /* 4210 */
SYS(sys_timer_settime, 4)
SYS(sys_timer_gettime, 2)
SYS(sys_timer_getoverrun, 1)
SYS(sys_timer_delete, 1)
SYS(sys_clock_gettime, 2) /* 4215 */
SYS(sys_clock_settime, 2)
SYS(sys_clock_getres, 2)
......@@ -894,12 +894,4 @@ sys_call_table:
.long sys_ni_syscall /* streams1 */
.long sys_ni_syscall /* streams2 */
.long sys_vfork
.long sys_timer_create /* 190 */
.long sys_timer_settime
.long sys_timer_gettime
.long sys_timer_getoverrun
.long sys_timer_delete
.long sys_clock_gettime /* 195 */
.long sys_clock_settime
.long sys_clock_getres /* 197 */
.space (NR_syscalls-197)*4
.space (NR_syscalls-183)*4
......@@ -68,8 +68,7 @@ sys_call_table:
/*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
/*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
/*255*/ .long sys_aplib, sys_timer_create, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
/*260*/ .long sys_timer_delete, sys_clock_gettime, sys_clock_settime, sys_clock_getres
/*255*/ .long sys_aplib, sys_nis_syscall
/* Now the SunOS syscall table. */
......
......@@ -68,8 +68,7 @@ sys_call_table32:
/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
/*255*/ .word sys_aplib, sys_timer_create, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
/*260*/ .word sys_timer_delete, sys_clock_gettime, sys_clock_settime, sys_clock_getres
.word sys_aplib
/* Now the 64-bit native Linux syscall table. */
......@@ -128,8 +127,7 @@ sys_call_table:
/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
/*255*/ .word sys_aplib, sys_timer_create, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
/*260*/ .word sys_timer_delete, sys_clock_gettime, sys_clock_settime, sys_clock_getres
.word sys_aplib
/* Now the 32-bit SunOS syscall table. */
......
......@@ -403,7 +403,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1;
if (maxsector < count || maxsector - count < sector) {
bh->b_state &= (1 << BH_Lock);
bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped);
/* This may well happen - the kernel calls bread()
without checking the size of the device, e.g.,
when mounting a device. */
......
......@@ -60,6 +60,8 @@ struct pp_struct {
unsigned int flags;
int irqresponse;
unsigned char irqctl;
struct ieee1284_info state;
struct ieee1284_info saved_state;
};
/* pp_struct.flags bitfields */
......@@ -348,6 +350,9 @@ static int pp_ioctl(struct inode *inode, struct file *file,
/* First handle the cases that don't take arguments. */
if (cmd == PPCLAIM) {
struct ieee1284_info *info;
int first_claim = 0;
if (pp->flags & PP_CLAIMED) {
printk (KERN_DEBUG CHRDEV
"%x: you've already got it!\n", minor);
......@@ -359,6 +364,8 @@ static int pp_ioctl(struct inode *inode, struct file *file,
int err = register_device (minor, pp);
if (err)
return err;
first_claim = 1;
}
parport_claim_or_block (pp->pdev);
......@@ -367,6 +374,30 @@ static int pp_ioctl(struct inode *inode, struct file *file,
/* For interrupt-reporting to work, we need to be
* informed of each interrupt. */
enable_irq (pp);
/* We may need to fix up the state machine. */
info = &pp->pdev->port->ieee1284;
pp->saved_state.mode = info->mode;
pp->saved_state.phase = info->phase;
if (pp->mode != info->mode) {
int phase = IEEE1284_PH_FWD_IDLE;
if (first_claim) {
info->mode = pp->mode;
switch (pp->mode & ~(IEEE1284_DEVICEID
| IEEE1284_ADDR)) {
case IEEE1284_MODE_NIBBLE:
case IEEE1284_MODE_BYTE:
phase = IEEE1284_PH_REV_IDLE;
}
info->phase = phase;
} else {
/* Just restore the state. */
info->mode = pp->state.mode;
info->phase = pp->state.phase;
}
}
return 0;
}
......@@ -406,6 +437,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
port = pp->pdev->port;
switch (cmd) {
struct ieee1284_info *info;
unsigned char reg;
unsigned char mask;
int mode;
......@@ -431,6 +463,12 @@ static int pp_ioctl(struct inode *inode, struct file *file,
return 0;
case PPRELEASE:
/* Save the state machine's state. */
info = &pp->pdev->port->ieee1284;
pp->state.mode = info->mode;
pp->state.phase = info->phase;
info->mode = pp->saved_state.mode;
info->phase = pp->saved_state.phase;
parport_release (pp->pdev);
pp->flags &= ~PP_CLAIMED;
return 0;
......
/* $Id: parport_ax.c,v 1.20 1999/07/03 08:56:21 davem Exp $
* Parallel-port routines for Sun Ultra/AX architecture
*
* Author: Eddie C. Dost <ecd@skynet.be>
*
* based on work by:
* Phil Blundell <Philip.Blundell@pobox.com>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Jose Renau <renau@acm.org>
* David Campbell <campbell@tirian.che.curtin.edu.au>
* Grant Guenther <grant@torque.net>
*/
#include <linux/string.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/parport.h>
#include <asm/ptrace.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/ebus.h>
#include <asm/ns87303.h>
#include <asm/irq.h>
/*
* Define this if you have Devices which don't support short
* host read/write cycles.
*/
#undef HAVE_SLOW_DEVICES
#define DATA 0x00
#define STATUS 0x01
#define CONTROL 0x02
#define EPPADDR 0x03
#define EPPDATA 0x04
#define CFIFO 0x400
#define DFIFO 0x400
#define TFIFO 0x400
#define CONFIGA 0x400
#define CONFIGB 0x401
#define ECONTROL 0x402
static void parport_ax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
parport_generic_irq(irq, (struct parport *) dev_id, regs);
}
void
parport_ax_write_epp(struct parport *p, unsigned char d)
{
outb(d, p->base + EPPDATA);
}
unsigned char
parport_ax_read_epp(struct parport *p)
{
return inb(p->base + EPPDATA);
}
void
parport_ax_write_epp_addr(struct parport *p, unsigned char d)
{
outb(d, p->base + EPPADDR);
}
unsigned char
parport_ax_read_epp_addr(struct parport *p)
{
return inb(p->base + EPPADDR);
}
int parport_ax_epp_clear_timeout(struct parport *pb);
int
parport_ax_check_epp_timeout(struct parport *p)
{
if (!(inb(p->base+STATUS) & 1))
return 0;
parport_ax_epp_clear_timeout(p);
return 1;
}
unsigned char
parport_ax_read_configb(struct parport *p)
{
return inb(p->base + CONFIGB);
}
void
parport_ax_write_data(struct parport *p, unsigned char d)
{
outb(d, p->base + DATA);
}
unsigned char
parport_ax_read_data(struct parport *p)
{
return inb(p->base + DATA);
}
void
parport_ax_write_control(struct parport *p, unsigned char d)
{
outb(d, p->base + CONTROL);
}
unsigned char
parport_ax_read_control(struct parport *p)
{
return inb(p->base + CONTROL);
}
unsigned char
parport_ax_frob_control(struct parport *p, unsigned char mask, unsigned char val)
{
unsigned char old = inb(p->base + CONTROL);
outb(((old & ~mask) ^ val), p->base + CONTROL);
return old;
}
void
parport_ax_write_status(struct parport *p, unsigned char d)
{
outb(d, p->base + STATUS);
}
unsigned char
parport_ax_read_status(struct parport *p)
{
return inb(p->base + STATUS);
}
void
parport_ax_write_econtrol(struct parport *p, unsigned char d)
{
outb(d, p->base + ECONTROL);
}
unsigned char
parport_ax_read_econtrol(struct parport *p)
{
return inb(p->base + ECONTROL);
}
unsigned char
parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val)
{
unsigned char old = inb(p->base + ECONTROL);
outb(((old & ~mask) ^ val), p->base + ECONTROL);
return old;
}
void
parport_ax_change_mode(struct parport *p, int m)
{
/* FIXME */
parport_ax_frob_econtrol(p, 0xe0, m << 5);
}
void
parport_ax_write_fifo(struct parport *p, unsigned char v)
{
outb(v, p->base + DFIFO);
}
unsigned char
parport_ax_read_fifo(struct parport *p)
{
return inb(p->base + DFIFO);
}
void
parport_ax_disable_irq(struct parport *p)
{
struct linux_ebus_dma *dma = p->private_data;
unsigned int dcsr;
dcsr = readl((unsigned long)&dma->dcsr);
dcsr &= ~(EBUS_DCSR_INT_EN);
writel(dcsr, (unsigned long)&dma->dcsr);
}
void
parport_ax_enable_irq(struct parport *p)
{
struct linux_ebus_dma *dma = p->private_data;
unsigned int dcsr;
dcsr = readl((unsigned long)&dma->dcsr);
dcsr |= EBUS_DCSR_INT_EN;
writel(dcsr, (unsigned long)&dma->dcsr);
}
void
parport_ax_init_state(struct pardevice *dev, struct parport_state *s)
{
struct linux_ebus_dma *dma = dev->port->private_data;
s->u.ax.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
s->u.ax.ecr = 0x0;
if (dev->irq_func)
s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
| EBUS_DCSR_INT_EN);
else
s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
& ~EBUS_DCSR_INT_EN);
}
void
parport_ax_save_state(struct parport *p, struct parport_state *s)
{
struct linux_ebus_dma *dma = p->private_data;
s->u.ax.ctr = parport_ax_read_control(p);
s->u.ax.ecr = parport_ax_read_econtrol(p);
s->u.ax.dcsr = readl((unsigned long)&dma->dcsr);
}
void
parport_ax_restore_state(struct parport *p, struct parport_state *s)
{
struct linux_ebus_dma *dma = p->private_data;
parport_ax_write_control(p, s->u.ax.ctr);
parport_ax_write_econtrol(p, s->u.ax.ecr);
writel(s->u.ax.dcsr, (unsigned long)&dma->dcsr);
}
void
parport_ax_inc_use_count(void)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
void
parport_ax_dec_use_count(void)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
static struct parport_operations parport_ax_ops =
{
parport_ax_write_data,
parport_ax_read_data,
parport_ax_write_control,
parport_ax_read_control,
parport_ax_frob_control,
parport_ax_read_status,
parport_ax_enable_irq,
parport_ax_disable_irq,
parport_ax_data_forward,
parport_ax_data_reverse,
parport_ax_interrupt,
parport_ax_init_state,
parport_ax_save_state,
parport_ax_restore_state,
parport_ax_inc_use_count,
parport_ax_dec_use_count,
parport_ieee1284_epp_write_data,
parport_ieee1284_epp_read_data,
parport_ieee1284_epp_write_addr,
parport_ieee1284_epp_read_addr,
parport_ieee1284_ecp_write_data,
parport_ieee1284_ecp_read_data,
parport_ieee1284_ecp_write_addr,
parport_ieee1284_write_compat,
parport_ieee1284_read_nibble,
parport_ieee1284_read_byte,
};
/******************************************************
* MODE detection section:
*/
/*
* Clear TIMEOUT BIT in EPP MODE
*/
int parport_ax_epp_clear_timeout(struct parport *pb)
{
unsigned char r;
if (!(parport_ax_read_status(pb) & 0x01))
return 1;
/* To clear timeout some chips require double read */
parport_ax_read_status(pb);
r = parport_ax_read_status(pb);
parport_ax_write_status(pb, r | 0x01); /* Some reset by writing 1 */
parport_ax_write_status(pb, r & 0xfe); /* Others by writing 0 */
r = parport_ax_read_status(pb);
return !(r & 0x01);
}
/* Check for ECP
*
* Old style XT ports alias io ports every 0x400, hence accessing ECONTROL
* on these cards actually accesses the CTR.
*
* Modern cards don't do this but reading from ECONTROL will return 0xff
* regardless of what is written here if the card does NOT support
* ECP.
*
* We will write 0x2c to ECONTROL and 0xcc to CTR since both of these
* values are "safe" on the CTR since bits 6-7 of CTR are unused.
*/
static int parport_ECR_present(struct parport *pb)
{
unsigned int r;
unsigned char octr = pb->ops->read_control(pb),
oecr = pb->ops->read_econtrol(pb);
r = pb->ops->read_control(pb);
if ((pb->ops->read_econtrol(pb) & 0x3) == (r & 0x3)) {
pb->ops->write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
r = pb->ops->read_control(pb);
if ((pb->ops->read_econtrol(pb) & 0x2) == (r & 0x2)) {
pb->ops->write_control(pb, octr);
return 0; /* Sure that no ECONTROL register exists */
}
}
if ((pb->ops->read_econtrol(pb) & 0x3 ) != 0x1)
return 0;
pb->ops->write_econtrol(pb, 0x34);
if (pb->ops->read_econtrol(pb) != 0x35)
return 0;
pb->ops->write_econtrol(pb, oecr);
pb->ops->write_control(pb, octr);
return PARPORT_MODE_PCECR;
}
static int parport_ECP_supported(struct parport *pb)
{
int i;
unsigned char oecr = pb->ops->read_econtrol(pb);
/* If there is no ECONTROL, we have no hope of supporting ECP. */
if (!(pb->modes & PARPORT_MODE_PCECR))
return 0;
/*
* Using LGS chipset it uses ECONTROL register, but
* it doesn't support ECP or FIFO MODE
*/
pb->ops->write_econtrol(pb, 0xc0); /* TEST FIFO */
for (i=0; i < 1024 && (pb->ops->read_econtrol(pb) & 0x01); i++)
pb->ops->write_fifo(pb, 0xaa);
pb->ops->write_econtrol(pb, oecr);
return (i == 1024) ? 0 : PARPORT_MODE_PCECP;
}
/* Detect PS/2 support.
*
* Bit 5 (0x20) sets the PS/2 data direction; setting this high
* allows us to read data from the data lines. In theory we would get back
* 0xff but any peripheral attached to the port may drag some or all of the
* lines down to zero. So if we get back anything that isn't the contents
* of the data register we deem PS/2 support to be present.
*
* Some SPP ports have "half PS/2" ability - you can't turn off the line
* drivers, but an external peripheral with sufficiently beefy drivers of
* its own can overpower them and assert its own levels onto the bus, from
* where they can then be read back as normal. Ports with this property
* and the right type of device attached are likely to fail the SPP test,
* (as they will appear to have stuck bits) and so the fact that they might
* be misdetected here is rather academic.
*/
static int parport_PS2_supported(struct parport *pb)
{
int ok = 0;
unsigned char octr = pb->ops->read_control(pb);
pb->ops->write_control(pb, octr | 0x20); /* try to tri-state buffer */
pb->ops->write_data(pb, 0x55);
if (pb->ops->read_data(pb) != 0x55) ok++;
pb->ops->write_data(pb, 0xaa);
if (pb->ops->read_data(pb) != 0xaa) ok++;
pb->ops->write_control(pb, octr); /* cancel input mode */
return ok ? PARPORT_MODE_PCPS2 : 0;
}
static int parport_ECPPS2_supported(struct parport *pb)
{
int mode;
unsigned char oecr = pb->ops->read_econtrol(pb);
if (!(pb->modes & PARPORT_MODE_PCECR))
return 0;
pb->ops->write_econtrol(pb, 0x20);
mode = parport_PS2_supported(pb);
pb->ops->write_econtrol(pb, oecr);
return mode ? PARPORT_MODE_PCECPPS2 : 0;
}
#define printmode(x) \
{ \
if (p->modes & PARPORT_MODE_PC##x) { \
printk("%s%s", f ? "," : "", #x); \
f++; \
} \
}
int
init_one_port(struct linux_ebus_device *dev)
{
struct parport tmpport, *p;
unsigned long base;
unsigned long config;
unsigned char tmp;
int irq, dma;
/* Pointer to NS87303 Configuration Registers */
config = dev->base_address[1];
/* Setup temporary access to Device operations */
tmpport.base = dev->base_address[0];
tmpport.ops = &parport_ax_ops;
/* Enable ECP mode, set bit 2 of the CTR first */
tmpport.ops->write_control(&tmpport, 0x04);
tmp = ns87303_readb(config, PCR);
tmp |= (PCR_EPP_IEEE | PCR_ECP_ENABLE | PCR_ECP_CLK_ENA);
ns87303_writeb(config, PCR, tmp);
/* LPT CTR bit 5 controls direction of parallel port */
tmp = ns87303_readb(config, PTR);
tmp |= PTR_LPT_REG_DIR;
ns87303_writeb(config, PTR, tmp);
/* Configure IRQ to Push Pull, Level Low */
tmp = ns87303_readb(config, PCR);
tmp &= ~(PCR_IRQ_ODRAIN);
tmp |= PCR_IRQ_POLAR;
ns87303_writeb(config, PCR, tmp);
#ifndef HAVE_SLOW_DEVICES
/* Enable Zero Wait State for ECP */
tmp = ns87303_readb(config, FCR);
tmp |= FCR_ZWS_ENA;
ns87303_writeb(config, FCR, tmp);
#endif
/*
* Now continue initializing the port
*/
base = dev->base_address[0];
irq = dev->irqs[0];
dma = PARPORT_DMA_AUTO;
if (!(p = parport_register_port(base, irq, dma, &parport_ax_ops)))
return 0;
/* Save away pointer to our EBus DMA */
p->private_data = (void *)dev->base_address[2];
p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p);
if (!check_region(p->base + 0x400, 3)) {
p->modes |= parport_ECR_present(p);
p->modes |= parport_ECP_supported(p);
p->modes |= parport_ECPPS2_supported(p);
}
p->size = 3;
if (p->dma == PARPORT_DMA_AUTO)
p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE;
printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
if (p->irq != PARPORT_IRQ_NONE)
printk(", irq %s", __irq_itoa(p->irq));
if (p->dma != PARPORT_DMA_NONE)
printk(", dma %d", p->dma);
printk(" [");
{
int f = 0;
printmode(SPP);
printmode(PS2);
printmode(ECP);
printmode(ECPPS2);
}
printk("]\n");
parport_proc_register(p);
if (p->irq != PARPORT_IRQ_NONE)
if ((err = request_irq(p->irq, parport_ax_interrupt,
0, p->name, p)) != 0)
return 0; /* @@@ FIXME */
request_region(p->base, p->size, p->name);
if (p->modes & PARPORT_MODE_PCECR)
request_region(p->base+0x400, 3, p->name);
request_region((unsigned long)p->private_data,
sizeof(struct linux_ebus_dma), p->name);
p->ops->write_control(p, 0x0c);
p->ops->write_data(p, 0);
/* Tell the high-level drivers about the port. */
parport_announce_port (p);
return 1;
}
EXPORT_NO_SYMBOLS;
#ifdef MODULE
int init_module(void)
#else
__initfunc(int parport_ax_init(void))
#endif
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
int count = 0;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "ecpp"))
count += init_one_port(edev);
}
}
return count ? 0 : -ENODEV;
}
#ifdef MODULE
void
cleanup_module(void)
{
struct parport *p = parport_enumerate(), *tmp;
while (p) {
tmp = p->next;
if (p->modes & PARPORT_MODE_PCSPP) {
if (p->irq != PARPORT_IRQ_NONE) {
parport_ax_disable_irq(p);
free_irq(p->irq, p);
}
release_region(p->base, p->size);
if (p->modes & PARPORT_MODE_PCECR)
release_region(p->base+0x400, 3);
release_region((unsigned long)p->private_data,
sizeof(struct linux_ebus_dma));
parport_proc_unregister(p);
parport_unregister_port(p);
}
p = tmp;
}
}
#endif
......@@ -1831,6 +1831,7 @@ void cleanup_module(void)
tmp = p->next;
if (p->modes & PARPORT_MODE_PCSPP) {
struct parport_pc_private *priv = p->private_data;
struct parport_operations *ops = p->ops;
if (p->dma != PARPORT_DMA_NONE)
free_dma(p->dma);
if (p->irq != PARPORT_IRQ_NONE)
......@@ -1844,8 +1845,8 @@ void cleanup_module(void)
if (priv->dma_buf)
free_page((unsigned long) priv->dma_buf);
kfree (p->private_data);
kfree (p->ops); /* hope no-one cached it */
parport_unregister_port(p);
kfree (ops); /* hope no-one cached it */
}
p = tmp;
}
......
......@@ -35,6 +35,9 @@ if [ ! "$CONFIG_USB" = "n" ]; then
dep_tristate ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
fi
dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
if [ "$CONFIG_PROC_FS" != "n" ]; then
bool 'Preliminary /proc/bus/usb support' CONFIG_USB_PROC
fi
fi
endmenu
......@@ -22,6 +22,9 @@ endif
ifeq ($(CONFIG_USB),m)
M_OBJS +=usbcore.o
MIX_OBJS +=usb.o usb-debug.o usb-core.o
ifeq ($(CONFIG_USB_PROC),y)
MIX_OBJS += proc_usb.o
endif
endif
ifeq ($(CONFIG_USB_UHCI),y)
......@@ -153,7 +156,10 @@ usb-ohci.o: ohci.o ohci-debug.o
usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o
$(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o
ifeq ($(CONFIG_USB_PROC),y)
usbcore.o: usb.o usb-debug.o usb-core.o proc_usb.o
$(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o proc_usb.o
else
usbcore.o: usb.o usb-debug.o usb-core.o
$(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o
endif
......@@ -27,7 +27,6 @@
/*****************************************************************************/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/socket.h>
#include <asm/uaccess.h>
......
......@@ -5,3 +5,5 @@ int usb_acm_init(void);
int usb_printer_init(void);
void usb_hub_cleanup(void);
void usb_mouse_cleanup(void);
int proc_usb_init (void);
void proc_usb_cleanup (void);
/*
* drivers/usb/proc_usb.c
* (C) Copyright 1999 Randy Dunlap.
*
* 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
*
*************************************************************
*
* This is a /proc/bus/usb filesystem output module for USB.
* It creates /proc/bus/usb/drivers and /proc/bus/usb/devices.
*
* /proc/bus/usb/devices contains USB topology, device, config, class,
* interface, & endpoint data.
*
* I considered using /proc/bus/usb/devices/device# for each device
* as it is attached or detached, but I didn't like this for some
* reason -- maybe it's just too deep of a directory structure.
* I also don't like looking in multiple places to gather and view
* the data. Having only one file for ./devices also prevents race
* conditions that could arise if a program was reading device info
* for devices that are being removed (unplugged). (That is, the
* program may find a directory for devnum_12 then try to open it,
* but it was just unplugged, so the directory is now deleted.
* But programs would just have to be prepared for situations like
* this in any plug-and-play environment.)
*/
#define __KERNEL__ 1
#include <linux/types.h>
#include <asm/types.h>
#include <linux/kernel.h>
/* #include <linux/module.h> */
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/list.h>
#include "usb.h"
#define DUMP_LIMIT (PAGE_SIZE - 100)
/* limit to only one memory page of output */
#define MAX_TOPO_LEVEL 6
static char *format_topo =
/* T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s */
"T: Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s If#=%3d MxCh=%2d Driver=%s\n";
static char *format_device1 =
/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
"D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
static char *format_device2 =
/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */
"P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
static char *format_config =
/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
"C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
static char *format_iface =
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx */
"I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
static char *format_endpt =
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
"E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n";
/*
* Need access to the driver and USB bus lists.
* extern struct list_head usb_driver_list;
* extern struct list_head usb_bus_list;
* However, these will come from functions that return ptrs to each of them.
*/
extern struct list_head *usb_driver_get_list (void);
extern struct list_head *usb_bus_get_list (void);
extern struct proc_dir_entry *proc_bus;
static struct proc_dir_entry *usbdir = NULL, *driversdir = NULL;
static struct proc_dir_entry *devicesdir = NULL;
struct class_info {
int class;
char *class_name;
};
struct class_info clas_info [] =
{ /* max. 5 chars. per name string */
{USB_CLASS_PER_INTERFACE, ">ifc"},
{USB_CLASS_AUDIO, "audio"},
{USB_CLASS_COMM, "comm."},
{USB_CLASS_HID, "HID"},
{USB_CLASS_HUB, "hub"},
{USB_CLASS_PRINTER, "print"},
{USB_CLASS_MASS_STORAGE, "stor."},
{USB_CLASS_VENDOR_SPEC, "vend."},
{-1, "unk."} /* leave as last */
};
/*****************************************************************/
static char *class_decode (const int class)
{
int ix;
for (ix = 0; clas_info [ix].class != -1; ix++)
if (clas_info [ix].class == class)
break;
return (clas_info [ix].class_name);
}
static int usb_dump_endpoint_descriptor (const struct usb_endpoint_descriptor *desc,
char *buf, int *len)
{
char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
*len += sprintf (buf + *len, format_endpt,
desc->bEndpointAddress,
(desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
desc->bmAttributes,
EndpointType[desc->bmAttributes & 3],
desc->wMaxPacketSize,
desc->bInterval
);
return (*len >= DUMP_LIMIT) ? -1 : 0;
}
static int usb_dump_endpoint (const struct usb_endpoint_descriptor *endpoint,
char *buf, int *len)
{
if (usb_dump_endpoint_descriptor (endpoint, buf, len) < 0)
return -1;
return 0;
}
static int usb_dump_interface_descriptor (const struct usb_interface_descriptor *desc,
char *buf, int *len)
{
*len += sprintf (buf + *len, format_iface,
desc->bInterfaceNumber,
desc->bAlternateSetting,
desc->bNumEndpoints,
desc->bInterfaceClass,
class_decode (desc->bInterfaceClass),
desc->bInterfaceSubClass,
desc->bInterfaceProtocol
);
return (*len >= DUMP_LIMIT) ? -1 : 0;
}
static int usb_dump_interface (const struct usb_interface_descriptor *interface,
char *buf, int *len)
{
int i;
if (usb_dump_interface_descriptor (interface, buf, len) < 0)
return -1;
for (i = 0; i < interface->bNumEndpoints; i++) {
if (usb_dump_endpoint (interface->endpoint + i, buf, len) < 0)
return -1;
}
return 0;
}
/* TBD:
* 0. TBDs
* 1. marking active config and ifaces (code lists all, but should mark
* which ones are active, if any)
* 2. Add proc_usb_init() call from usb-core.c.
* 3. proc_usb as a MODULE ?
* 4. use __initfunc() ?
* 5. add <halted> status to each endpoint line
*/
static int usb_dump_config_descriptor (const struct usb_config_descriptor *desc,
const int active, char *buf, int *len)
{
*len += sprintf (buf + *len, format_config,
active ? '*' : ' ', /* mark active/actual/current cfg. */
desc->bNumInterfaces,
desc->bConfigurationValue,
desc->bmAttributes,
desc->MaxPower * 2
);
return (*len >= DUMP_LIMIT) ? -1 : 0;
}
static int usb_dump_config (const struct usb_config_descriptor *config,
const int active, char *buf, int *len)
{
int i, j;
struct usb_alternate_setting *as;
if (!config) { /* getting these some in 2.3.7; none in 2.3.6 */
*len += sprintf (buf + *len, "(null Cfg. desc.)\n");
return 0;
}
if (usb_dump_config_descriptor (config, active, buf, len) < 0)
return -1;
for (i = 0; i < config->num_altsetting; i++) {
as = config->altsetting + i;
if ((as) == NULL)
break;
for (j = 0; j < config->bNumInterfaces; j++)
if (usb_dump_interface (as->interface + j, buf, len) < 0)
return -1;
}
return 0;
}
/*
* Dump the different USB descriptors.
*/
static int usb_dump_device_descriptor (const struct usb_device_descriptor *desc,
char *buf, int *len)
{
*len += sprintf (buf + *len, format_device1,
desc->bcdUSB >> 8, desc->bcdUSB & 0xff,
desc->bDeviceClass,
class_decode (desc->bDeviceClass),
desc->bDeviceSubClass,
desc->bDeviceProtocol,
desc->bMaxPacketSize0,
desc->bNumConfigurations
);
if (*len >= DUMP_LIMIT) return -1;
*len += sprintf (buf + *len, format_device2,
desc->idVendor, desc->idProduct,
desc->bcdDevice >> 8, desc->bcdDevice & 0xff
);
return (*len >= DUMP_LIMIT) ? -1 : 0;
}
static int usb_dump_desc (const struct usb_device *dev, char *buf, int *len)
{
int i;
if (usb_dump_device_descriptor (&dev->descriptor, buf, len) < 0)
return -1;
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (usb_dump_config (dev->config + i,
(dev->config + i) == dev->actconfig, /* active ? */
buf, len) < 0)
return -1;
}
return 0;
}
#ifdef PROC_EXTRA /* TBD: may want to add this code later */
static int usb_dump_hub_descriptor (const struct usb_hub_descriptor * desc,
char *buf, int *len)
{
int leng = USB_DT_HUB_NONVAR_SIZE;
unsigned char *ptr = (unsigned char *) desc;
*len += sprintf (buf + *len, "Interface:");
while (leng) {
*len += sprintf (buf + *len, " %02x", *ptr);
ptr++; leng--;
}
*len += sprintf (buf + *len, "\n");
return (*len >= DUMP_LIMIT) ? -1 : 0;
}
static int usb_dump_string (const struct usb_device *dev, char *id, int index,
char *buf, int *len)
{
if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
*len += sprintf (buf + *len, "%s: %s ", id, dev->stringindex[index]);
return (*len >= DUMP_LIMIT) ? -1 : 0;
}
#endif /* PROC_EXTRA */
/*****************************************************************/
static int usb_device_dump (char *buf, int *len,
const struct usb_device *usbdev,
int level, int index, int count)
{
int chix;
int cnt = 0;
int parent_devnum;
if (level > MAX_TOPO_LEVEL) return -1;
parent_devnum = usbdev->parent ? (usbdev->parent->devnum == -1) ? 0
: usbdev->parent->devnum : 0;
/*
* So the root hub's parent is 0 and any device that is
* plugged into the root hub has a parent of 0.
*/
*len += sprintf (buf + *len, format_topo,
level, parent_devnum, index, count,
usbdev->devnum,
usbdev->slow ? "1.5" : "12 ",
usbdev->ifnum, usbdev->maxchild,
usbdev->driver ? usbdev->driver->name :
(level == 0) ? "(root hub)" : "(none)"
);
/*
* level = topology-tier level;
* parent_devnum = parent device number;
* index = parent's connector number;
* count = device count at this level
*/
if (*len >= DUMP_LIMIT)
return -1;
if (usbdev->devnum > 0) { /* for any except root hub */
if (usb_dump_desc (usbdev, buf, len) < 0)
return -1;
}
/* Now look at all of this device's children. */
for (chix = 0; chix < usbdev->maxchild; chix++) {
if (usbdev->children [chix]) {
if (usb_device_dump (buf, len,
usbdev->children [chix],
level + 1, chix, ++cnt) < 0)
return -1;
}
}
return 0;
}
static int usb_bus_list_dump (char *buf, int len)
{
struct list_head *usb_bus_list = usb_bus_get_list ();
struct list_head *list = usb_bus_list->next;
len = 0;
/*
* Go thru each usb_bus. Within each usb_bus: each usb_device.
* Within each usb_device: all of its device & config. descriptors,
* marking the currently active ones.
*/
while (list != usb_bus_list) {
struct usb_bus *bus = list_entry (list, struct usb_bus, bus_list);
if (usb_device_dump (buf, &len, bus->root_hub, 0, 0, 0)
< 0)
break;
list = list->next;
if (len >= DUMP_LIMIT) {
len += sprintf (buf + len, "(truncated)\n");
break;
}
}
return (len);
}
static int usb_bus_list_dump_devices (char *buf, char **start, off_t offset,
int len, int *eof, void *data)
{
return usb_bus_list_dump (buf, len);
}
/*
* Dump usb_driver_list.
*
* We now walk the list of registered USB drivers.
*/
static int usb_driver_list_dump (char *buf, char **start, off_t offset,
int len, int *eof, void *data)
{
struct list_head *usb_driver_list = usb_driver_get_list ();
struct list_head *tmp = usb_driver_list->next;
int cnt = 0;
len = 0;
while (tmp != usb_driver_list) {
struct usb_driver *driver = list_entry (tmp, struct usb_driver,
driver_list);
len += sprintf (buf + len, "%s\n", driver->name);
cnt++;
tmp = tmp->next;
if (len >= DUMP_LIMIT)
{
len += sprintf (buf + len, "(truncated)\n");
return (len);
}
}
if (!cnt)
len += sprintf (buf + len, "(none)\n");
return (len);
}
void proc_usb_cleanup (void)
{
if (driversdir)
remove_proc_entry ("drivers", usbdir);
if (devicesdir)
remove_proc_entry ("devices", usbdir);
if (usbdir)
remove_proc_entry ("usb", proc_bus);
}
int proc_usb_init (void)
{
usbdir = create_proc_entry ("usb", S_IFDIR, proc_bus);
if (!usbdir) {
printk ("proc_usb: cannot create /proc/bus/usb entry\n");
return -1;
}
driversdir = create_proc_entry ("drivers", 0, usbdir);
if (!driversdir) {
printk ("proc_usb: cannot create /proc/bus/usb/drivers entry\n");
proc_usb_cleanup ();
return -1;
}
driversdir->read_proc = usb_driver_list_dump;
devicesdir = create_proc_entry ("devices", 0, usbdir);
if (!devicesdir) {
printk ("proc_usb: cannot create /proc/bus/usb/devices entry\n");
proc_usb_cleanup ();
return -1;
}
devicesdir->read_proc = usb_bus_list_dump_devices;
return 0;
}
#ifdef PROCFS_MODULE /* TBD: support proc_fs MODULE ??? */
int init_module (void)
{
return proc_usb_init ();
}
void cleanup_module (void)
{
proc_usb_cleanup ();
}
#endif /* PROCFS_MODULE */
/* end proc_usb.c */
#!/usr/bin/perl
# Reads /proc/bus/usb/devices and selectively lists and/or
# interprets it.
$DEVFILENAME = "/proc/bus/usb/devices";
$PROGNAME = $0;
$TAGS = $ARGV[0]; # save user TAGS
if (length ($TAGS) == 0)
{
print "usage: $PROGNAME tags\n";
print " where 'tags' can be any number of 'TDPCIE' or 'A(LL)'\n";
exit 1;
}
$ALL = ($TAGS =~ /all/i) || ($TAGS =~ /a/i);
# TBD: Check that $TAGS is valid.
if (! $ALL)
{
}
if (! open (DEVNUM, "<$DEVFILENAME"))
{
print "$PROGNAME: cannot open '$DEVFILENAME'\n";
exit 1;
}
while ($line = <DEVNUM>) # read a text line from DEVNUM
{
if (($ALL) || ($line =~ /^[$TAGS]:/i)) # any of TAGS at beg. of line?
{
print "$line"; # still has newline char on it
# TBD: add more/paging functionality.
}
} # end while DEVNUM
close (DEVNUM);
# END.
......@@ -28,6 +28,7 @@
# endif
#endif
int usb_init(void)
{
#ifndef CONFIG_USB_MODULE
......@@ -64,6 +65,9 @@ int usb_init(void)
# ifdef CONFIG_USB_SCSI
usb_scsi_init();
# endif
#endif
#ifdef CONFIG_USB_PROC
proc_usb_init ();
#endif
return 0;
}
......@@ -72,6 +76,9 @@ int usb_init(void)
*/
void cleanup_drivers(void)
{
#ifdef CONFIG_USB_PROC
proc_usb_cleanup ();
#endif
#ifndef MODULE
# ifdef CONFIG_USB_HUB
usb_hub_cleanup();
......
......@@ -36,6 +36,7 @@
* 6 wLength 2 Count Bytes for data
*/
#include <linux/config.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/malloc.h>
......@@ -1140,3 +1141,15 @@ int usb_release_irq(struct usb_device *dev, void* handle)
{
return dev->bus->op->release_irq(handle);
}
#ifdef CONFIG_PROC_FS
struct list_head * usb_driver_get_list (void)
{
return &usb_driver_list;
}
struct list_head * usb_bus_get_list (void)
{
return &usb_bus_list;
}
#endif
......@@ -42,6 +42,8 @@
* Alan Cox : security fixes.
* <Alan.Cox@linux.org>
*
* Al Viro : safe handling of mm_struct
*
*/
#include <linux/types.h>
......@@ -386,21 +388,15 @@ static int get_cmdline(char * buffer)
return sprintf(buffer, "%s\n", saved_command_line);
}
static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
static unsigned long get_phys_addr(struct mm_struct * mm, unsigned long ptr)
{
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
if (!p || !p->mm || ptr >= TASK_SIZE)
return 0;
/* Check for NULL pgd .. shouldn't happen! */
if (!p->mm->pgd) {
printk("get_phys_addr: pid %d has NULL pgd!\n", p->pid);
if (ptr >= TASK_SIZE)
return 0;
}
page_dir = pgd_offset(p->mm,ptr);
page_dir = pgd_offset(mm,ptr);
if (pgd_none(*page_dir))
return 0;
if (pgd_bad(*page_dir)) {
......@@ -422,7 +418,7 @@ static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
return pte_page(pte) + (ptr & ~PAGE_MASK);
}
static int get_array(struct task_struct *p, unsigned long start, unsigned long end, char * buffer)
static int get_array(struct mm_struct *mm, unsigned long start, unsigned long end, char * buffer)
{
unsigned long addr;
int size = 0, result = 0;
......@@ -431,7 +427,7 @@ static int get_array(struct task_struct *p, unsigned long start, unsigned long e
if (start >= end)
return result;
for (;;) {
addr = get_phys_addr(p, start);
addr = get_phys_addr(mm, start);
if (!addr)
return result;
do {
......@@ -451,29 +447,42 @@ static int get_array(struct task_struct *p, unsigned long start, unsigned long e
return result;
}
static int get_env(int pid, char * buffer)
static struct mm_struct *get_mm(int pid)
{
struct task_struct *p;
struct mm_struct *mm = NULL;
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (p)
mm = p->mm;
if (mm)
atomic_inc(&mm->mm_users);
read_unlock(&tasklist_lock);
return mm;
}
if (!p || !p->mm)
return 0;
return get_array(p, p->mm->env_start, p->mm->env_end, buffer);
static int get_env(int pid, char * buffer)
{
struct mm_struct *mm = get_mm(pid);
int res = 0;
if (mm) {
res = get_array(mm, mm->env_start, mm->env_end, buffer);
mmput(mm);
}
return res;
}
static int get_arg(int pid, char * buffer)
{
struct task_struct *p;
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!p || !p->mm)
return 0;
return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer);
struct mm_struct *mm = get_mm(pid);
int res = 0;
if (mm) {
res = get_array(mm, mm->arg_start, mm->arg_end, buffer);
mmput(mm);
}
return res;
}
/*
......@@ -740,48 +749,44 @@ static inline char * task_state(struct task_struct *p, char *buffer)
return buffer;
}
static inline char * task_mem(struct task_struct *p, char *buffer)
static inline char * task_mem(struct mm_struct *mm, char *buffer)
{
struct mm_struct * mm = p->mm;
if (mm) {
struct vm_area_struct * vma;
unsigned long data = 0, stack = 0;
unsigned long exec = 0, lib = 0;
down(&mm->mmap_sem);
for (vma = mm->mmap; vma; vma = vma->vm_next) {
unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
if (!vma->vm_file) {
data += len;
if (vma->vm_flags & VM_GROWSDOWN)
stack += len;
continue;
}
if (vma->vm_flags & VM_WRITE)
struct vm_area_struct * vma;
unsigned long data = 0, stack = 0;
unsigned long exec = 0, lib = 0;
down(&mm->mmap_sem);
for (vma = mm->mmap; vma; vma = vma->vm_next) {
unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
if (!vma->vm_file) {
data += len;
if (vma->vm_flags & VM_GROWSDOWN)
stack += len;
continue;
}
if (vma->vm_flags & VM_WRITE)
continue;
if (vma->vm_flags & VM_EXEC) {
exec += len;
if (vma->vm_flags & VM_EXECUTABLE)
continue;
if (vma->vm_flags & VM_EXEC) {
exec += len;
if (vma->vm_flags & VM_EXECUTABLE)
continue;
lib += len;
}
lib += len;
}
buffer += sprintf(buffer,
"VmSize:\t%8lu kB\n"
"VmLck:\t%8lu kB\n"
"VmRSS:\t%8lu kB\n"
"VmData:\t%8lu kB\n"
"VmStk:\t%8lu kB\n"
"VmExe:\t%8lu kB\n"
"VmLib:\t%8lu kB\n",
mm->total_vm << (PAGE_SHIFT-10),
mm->locked_vm << (PAGE_SHIFT-10),
mm->rss << (PAGE_SHIFT-10),
data - stack, stack,
exec - lib, lib);
up(&mm->mmap_sem);
}
buffer += sprintf(buffer,
"VmSize:\t%8lu kB\n"
"VmLck:\t%8lu kB\n"
"VmRSS:\t%8lu kB\n"
"VmData:\t%8lu kB\n"
"VmStk:\t%8lu kB\n"
"VmExe:\t%8lu kB\n"
"VmLib:\t%8lu kB\n",
mm->total_vm << (PAGE_SHIFT-10),
mm->locked_vm << (PAGE_SHIFT-10),
mm->rss << (PAGE_SHIFT-10),
data - stack, stack,
exec - lib, lib);
up(&mm->mmap_sem);
return buffer;
}
......@@ -842,44 +847,61 @@ static int get_status(int pid, char * buffer)
{
char * orig = buffer;
struct task_struct *tsk;
struct mm_struct *mm = NULL;
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
if (tsk)
mm = tsk->mm;
if (mm)
atomic_inc(&mm->mm_users);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
buffer = task_name(tsk, buffer);
buffer = task_state(tsk, buffer);
buffer = task_mem(tsk, buffer);
if (mm)
buffer = task_mem(mm, buffer);
buffer = task_sig(tsk, buffer);
buffer = task_cap(tsk, buffer);
if (mm)
mmput(mm);
return buffer - orig;
}
static int get_stat(int pid, char * buffer)
{
struct task_struct *tsk;
struct mm_struct *mm = NULL;
unsigned long vsize, eip, esp, wchan;
long priority, nice;
int tty_pgrp;
sigset_t sigign, sigcatch;
char state;
int res;
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
if (tsk)
mm = tsk->mm;
if (mm)
atomic_inc(&mm->mm_users);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
state = *get_task_state(tsk);
vsize = eip = esp = 0;
if (tsk->mm) {
struct vm_area_struct *vma = tsk->mm->mmap;
if (mm) {
struct vm_area_struct *vma;
down(&mm->mmap_sem);
vma = mm->mmap;
while (vma) {
vsize += vma->vm_end - vma->vm_start;
vma = vma->vm_next;
}
eip = KSTK_EIP(tsk);
esp = KSTK_ESP(tsk);
up(&mm->mmap_sem);
}
wchan = get_wchan(tsk);
......@@ -898,7 +920,7 @@ static int get_stat(int pid, char * buffer)
nice = tsk->priority;
nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY;
return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
pid,
......@@ -924,11 +946,11 @@ static int get_stat(int pid, char * buffer)
tsk->it_real_value,
tsk->start_time,
vsize,
tsk->mm ? tsk->mm->rss : 0, /* you might want to shift this left 3 */
mm ? mm->rss : 0, /* you might want to shift this left 3 */
tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0,
tsk->mm ? tsk->mm->start_code : 0,
tsk->mm ? tsk->mm->end_code : 0,
tsk->mm ? tsk->mm->start_stack : 0,
mm ? mm->start_code : 0,
mm ? mm->end_code : 0,
mm ? mm->start_stack : 0,
esp,
eip,
/* The signal information here is obsolete.
......@@ -944,6 +966,9 @@ static int get_stat(int pid, char * buffer)
tsk->cnswap,
tsk->exit_signal,
tsk->processor);
if (mm)
mmput(mm);
return res;
}
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
......@@ -1021,19 +1046,15 @@ static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long en
static int get_statm(int pid, char * buffer)
{
struct task_struct *tsk;
struct mm_struct *mm = get_mm(pid);
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
if (tsk->mm) {
struct vm_area_struct * vma = tsk->mm->mmap;
if (mm) {
struct vm_area_struct * vma;
down(&mm->mmap_sem);
vma = mm->mmap;
while (vma) {
pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
pgd_t *pgd = pgd_offset(mm, vma->vm_start);
int pages = 0, shared = 0, dirty = 0, total = 0;
statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
......@@ -1051,6 +1072,8 @@ static int get_statm(int pid, char * buffer)
drs += pages;
vma = vma->vm_next;
}
up(&mm->mmap_sem);
mmput(mm);
}
return sprintf(buffer,"%d %d %d %d %d %d %d\n",
size, resident, share, trs, lrs, drs, dt);
......
......@@ -82,63 +82,70 @@ static struct dentry * proc_follow_link(struct dentry *dentry,
ino &= 0x0000ffff;
result = ERR_PTR(-ENOENT);
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
if (!p)
goto out_unlock;
switch (ino) {
case PROC_PID_CWD:
if (!p->fs || !p->fs->pwd)
goto out_unlock;
result = p->fs->pwd;
goto out_dget;
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
if (p && p->fs && p->fs->pwd)
result = dget(p->fs->pwd);
read_unlock(&tasklist_lock);
break;
case PROC_PID_ROOT:
if (!p->fs || !p->fs->root)
goto out_unlock;
result = p->fs->root;
goto out_dget;
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
if (p && p->fs && p->fs->root)
result = dget(p->fs->root);
read_unlock(&tasklist_lock);
break;
case PROC_PID_EXE: {
struct mm_struct *mm = NULL;
struct vm_area_struct * vma;
if (!p->mm)
goto out_unlock;
down(&p->mm->mmap_sem);
vma = p->mm->mmap;
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
if (p)
mm = p->mm;
if (mm)
atomic_inc(&mm->mm_users);
read_unlock(&tasklist_lock);
if (!mm)
break;
down(&mm->mmap_sem);
vma = mm->mmap;
while (vma) {
if ((vma->vm_flags & VM_EXECUTABLE) &&
vma->vm_file) {
result = vma->vm_file->f_dentry;
up(&p->mm->mmap_sem);
goto out_dget;
result = dget(vma->vm_file->f_dentry);
break;
}
vma = vma->vm_next;
}
up(&p->mm->mmap_sem);
goto out_unlock;
up(&mm->mmap_sem);
mmput(mm);
break;
}
default:
if (ino & PROC_PID_FD_DIR) {
struct file * file;
struct files_struct *files = NULL;
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
if (p)
files = p->files;
read_unlock(&tasklist_lock);
if (!files)
break;
ino &= 0x7fff;
if (!p->files) /* shouldn't happen here */
goto out_unlock;
read_lock(&p->files->file_lock);
file = fcheck_task(p, ino);
if (!file || !file->f_dentry)
goto out_unlock;
result = file->f_dentry;
read_lock(&files->file_lock);
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
if (ino < files->max_fds &&
(file = files->fd[ino]) && file->f_dentry)
result = dget(file->f_dentry);
read_unlock(&p->files->file_lock);
goto out_dget;
}
}
out_dget:
result = dget(result);
out_unlock:
read_unlock(&tasklist_lock);
out:
return result;
}
......
......@@ -67,8 +67,6 @@ typedef struct siginfo {
*/
#define si_pid _sifields._kill._pid
#define si_uid _sifields._kill._uid
#define si_timer1 _sifields._timer._timer1
#define si_timer2 _sifields._timer._timer2
#define si_status _sifields._sigchld._status
#define si_utime _sifields._sigchld._utime
#define si_stime _sifields._sigchld._stime
......
......@@ -308,14 +308,6 @@
#define __NR_capget 368
#define __NR_capset 369
#define __NR_sendfile 370
#define __NR_timer_create 371
#define __NR_timer_settime 372
#define __NR_timer_gettime 373
#define __NR_timer_getoverrun 374
#define __NR_timer_delete 375
#define __NR_clock_gettime 376
#define __NR_clock_settime 377
#define __NR_clock_getres 378
#if defined(__LIBRARY__) && defined(__GNUC__)
......
......@@ -67,8 +67,6 @@ typedef struct siginfo {
*/
#define si_pid _sifields._kill._pid
#define si_uid _sifields._kill._uid
#define si_timer1 _sifields._timer._timer1
#define si_timer2 _sifields._timer._timer2
#define si_status _sifields._sigchld._status
#define si_utime _sifields._sigchld._utime
#define si_stime _sifields._sigchld._stime
......
......@@ -198,14 +198,6 @@
/* 188 reserved */
/* 189 reserved */
#define __NR_vfork (__NR_SYSCALL_BASE+190)
#define __NR_timer_create (__NR_SYSCALL_BASE+191)
#define __NR_timer_settime (__NR_SYSCALL_BASE+192)
#define __NR_timer_gettime (__NR_SYSCALL_BASE+193)
#define __NR_timer_getoverrun (__NR_SYSCALL_BASE+194)
#define __NR_timer_delete (__NR_SYSCALL_BASE+195)
#define __NR_clock_gettime (__NR_SYSCALL_BASE+196)
#define __NR_clock_settime (__NR_SYSCALL_BASE+197)
#define __NR_clock_getres (__NR_SYSCALL_BASE+198)
#define __sys2(x) #x
#define __sys1(x) __sys2(x)
......
......@@ -2,6 +2,7 @@
#define __I386_MMU_CONTEXT_H
#include <asm/desc.h>
#include <asm/atomic.h>
/*
* possibly do the LDT unload here?
......@@ -11,20 +12,19 @@
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, unsigned cpu)
{
unsigned long vm_mask;
/*
* Re-load LDT if necessary
*/
if (prev->segments != next->segments)
load_LDT(next);
if (prev != next) {
/*
* Re-load LDT if necessary
*/
if (prev->segments != next->segments)
load_LDT(next);
/* Re-load page tables */
asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd)));
vm_mask = 1UL << cpu;
next->cpu_vm_mask |= vm_mask;
prev->cpu_vm_mask &= ~vm_mask;
/* Re-load page tables */
asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd)));
clear_bit(cpu, &prev->cpu_vm_mask);
}
set_bit(cpu, &next->cpu_vm_mask);
}
#endif
......@@ -31,14 +31,13 @@ typedef struct siginfo {
struct {
unsigned int _timer1;
unsigned int _timer2;
sigval_t _sigval2; /* FIXME: must map to _sigval below because it is the same */
} _timer;
/* POSIX.1b signals */
struct {
pid_t _pid; /* sender's pid */
uid_t _uid; /* sender's uid */
sigval_t _sigval; /* FIXME: move out of union together with _sigval2 */
sigval_t _sigval;
} _rt;
/* SIGCHLD */
......@@ -68,8 +67,6 @@ typedef struct siginfo {
*/
#define si_pid _sifields._kill._pid
#define si_uid _sifields._kill._uid
#define si_timer1 _sifields._timer._timer1
#define si_timer2 _sifields._timer._timer2
#define si_status _sifields._sigchld._status
#define si_utime _sifields._sigchld._utime
#define si_stime _sifields._sigchld._stime
......
......@@ -195,14 +195,6 @@
#define __NR_getpmsg 188 /* some people actually want streams */
#define __NR_putpmsg 189 /* some people actually want streams */
#define __NR_vfork 190
#define __NR_timer_create 191
#define __NR_timer_settime 192
#define __NR_timer_gettime 193
#define __NR_timer_getoverrun 194
#define __NR_timer_delete 195
#define __NR_clock_gettime 196
#define __NR_clock_settime 197
#define __NR_clock_getres 198
/* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */
......
......@@ -67,8 +67,6 @@ typedef struct siginfo {
*/
#define si_pid _sifields._kill._pid
#define si_uid _sifields._kill._uid
#define si_timer1 _sifields._timer._timer1
#define si_timer2 _sifields._timer._timer2
#define si_status _sifields._sigchld._status
#define si_utime _sifields._sigchld._utime
#define si_stime _sifields._sigchld._stime
......
......@@ -194,14 +194,6 @@
#define __NR_getpmsg 188 /* some people actually want streams */
#define __NR_putpmsg 189 /* some people actually want streams */
#define __NR_vfork 190
#define __NR_timer_create 191
#define __NR_timer_settime 192
#define __NR_timer_gettime 193
#define __NR_timer_getoverrun 194
#define __NR_timer_delete 195
#define __NR_clock_gettime 196
#define __NR_clock_settime 197
#define __NR_clock_getres 198
/* user-visible error numbers are in the range -1 - -122: see
<asm-m68k/errno.h> */
......
......@@ -75,8 +75,6 @@ typedef struct siginfo {
*/
#define si_pid _sifields._kill._pid
#define si_uid _sifields._kill._uid
#define si_timer1 _sifields._timer._timer1
#define si_timer2 _sifields._timer._timer2
#define si_status _sifields._sigchld._status
#define si_utime _sifields._sigchld._utime
#define si_stime _sifields._sigchld._stime
......
......@@ -1196,14 +1196,6 @@
#define __NR_sendfile (__NR_Linux + 207)
#define __NR_getpmsg (__NR_Linux + 208)
#define __NR_putpmsg (__NR_Linux + 209)
#define __NR_timer_create (__NR_Linux + 210)
#define __NR_timer_settime (__NR_Linux + 211)
#define __NR_timer_gettime (__NR_Linux + 212)
#define __NR_timer_getoverrun (__NR_Linux + 213)
#define __NR_timer_delete (__NR_Linux + 214)
#define __NR_clock_gettime (__NR_Linux + 215)
#define __NR_clock_settime (__NR_Linux + 216)
#define __NR_clock_getres (__NR_Linux + 217)
/*
* Offset of the last Linux flavoured syscall
......
......@@ -67,8 +67,6 @@ typedef struct siginfo {
*/
#define si_pid _sifields._kill._pid
#define si_uid _sifields._kill._uid
#define si_timer1 _sifields._timer._timer1
#define si_timer2 _sifields._timer._timer2
#define si_status _sifields._sigchld._status
#define si_utime _sifields._sigchld._utime
#define si_stime _sifields._sigchld._stime
......@@ -124,7 +122,7 @@ typedef struct siginfo {
* SIGSEGV si_codes
*/
#define SEGV_MAPERR 1 /* address not mapped to object */
#define SEGV_ACCERR 2 /* invalid permissions for mapped object */
#define SRGV_ACCERR 2 /* invalid permissions for mapped object */
#define NSIGSEGV 2
/*
......
......@@ -194,14 +194,6 @@
#define __NR_getpmsg 187 /* some people actually want streams */
#define __NR_putpmsg 188 /* some people actually want streams */
#define __NR_vfork 189
#define __NR_timer_create 190
#define __NR_timer_settime 191
#define __NR_timer_gettime 192
#define __NR_timer_getoverrun 193
#define __NR_timer_delete 194
#define __NR_clock_gettime 195
#define __NR_clock_settime 196
#define __NR_clock_getres 197
#define __NR(n) #n
......
......@@ -70,8 +70,6 @@ typedef struct siginfo {
*/
#define si_pid _sifields._kill._pid
#define si_uid _sifields._kill._uid
#define si_timer1 _sifields._timer._timer1
#define si_timer2 _sifields._timer._timer2
#define si_status _sifields._sigchld._status
#define si_utime _sifields._sigchld._utime
#define si_stime _sifields._sigchld._stime
......@@ -128,7 +126,7 @@ typedef struct siginfo {
* SIGSEGV si_codes
*/
#define SEGV_MAPERR 1 /* address not mapped to object */
#define SEGV_ACCERR 2 /* invalid permissions for mapped object */
#define SRGV_ACCERR 2 /* invalid permissions for mapped object */
#define NSIGSEGV 2
/*
......
......@@ -271,14 +271,6 @@
#define __NR_fdatasync 253
#define __NR_nfsservctl 254
#define __NR_aplib 255
#define __NR_timer_create 256
#define __NR_timer_settime 257
#define __NR_timer_gettime 258
#define __NR_timer_getoverrun 259
#define __NR_timer_delete 260
#define __NR_clock_gettime 261
#define __NR_clock_settime 262
#define __NR_clock_getres 263
#define _syscall0(type,name) \
type name(void) \
......
......@@ -129,8 +129,6 @@ typedef struct siginfo32 {
*/
#define si_pid _sifields._kill._pid
#define si_uid _sifields._kill._uid
#define si_timer1 _sifields._timer._timer1
#define si_timer2 _sifields._timer._timer2
#define si_status _sifields._sigchld._status
#define si_utime _sifields._sigchld._utime
#define si_stime _sifields._sigchld._stime
......@@ -187,7 +185,7 @@ typedef struct siginfo32 {
* SIGSEGV si_codes
*/
#define SEGV_MAPERR 1 /* address not mapped to object */
#define SEGV_ACCERR 2 /* invalid permissions for mapped object */
#define SRGV_ACCERR 2 /* invalid permissions for mapped object */
#define NSIGSEGV 2
/*
......
......@@ -271,14 +271,6 @@
#define __NR_fdatasync 253
#define __NR_nfsservctl 254
#define __NR_aplib 255
#define __NR_timer_create 256
#define __NR_timer_settime 257
#define __NR_timer_gettime 258
#define __NR_timer_getoverrun 259
#define __NR_timer_delete 260
#define __NR_clock_gettime 261
#define __NR_clock_settime 262
#define __NR_clock_getres 263
#define _syscall0(type,name) \
type name(void) \
......
......@@ -14,8 +14,6 @@
#define PATH_MAX 4095 /* # chars in a path name */
#define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */
#define MAX_ITIMERS 32 /* # POSIX.1b itimers per process */
#define RTSIG_MAX 32
#endif
......@@ -35,7 +35,6 @@ extern unsigned long event;
#define CLONE_PID 0x00001000 /* set if pid shared */
#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */
#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */
#define CLONE_ITIMERS 0x00008000 /* set if POSIX.1b itimers are shared */
/*
* These are the constant used to fake the fixed-point load-average
......@@ -240,26 +239,6 @@ struct signal_struct {
*/
struct user_struct;
/* POSIX.1b interval timer structure. */
struct k_itimer {
spinlock_t it_lock;
clockid_t it_clock; /* which timer type */
timer_t it_id; /* timer id */
int it_overrun; /* number of signals overrun */
struct sigevent it_signal; /* signal to be delivered */
struct timespec it_interval; /* interval (rounded to jiffies) */
int it_incr; /* interval specified in jiffies */
struct task_struct *it_process; /* process to send signal to */
struct timer_list it_timer;
};
/* Structure to maintain the dynamically created POSIX.1b interval timers. */
struct itimer_struct {
atomic_t count;
spinlock_t its_lock;
struct k_itimer *itimer[MAX_ITIMERS];
};
struct task_struct {
/* these are hardcoded - don't touch */
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
......@@ -315,7 +294,6 @@ struct task_struct {
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
struct itimer_struct *posix_timers; /* POSIX.1b Interval Timers */
struct tms times;
unsigned long start_time;
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
......@@ -353,7 +331,6 @@ struct task_struct {
spinlock_t sigmask_lock; /* Protects signal and blocked */
struct signal_struct *sig;
sigset_t signal, blocked;
siginfo_t nrt_info[SIGRTMIN]; /* siginfo for non RT signals */
struct signal_queue *sigqueue, **sigqueue_tail;
unsigned long sas_ss_sp;
size_t sas_ss_size;
......@@ -403,7 +380,6 @@ struct task_struct {
/* chld wait */ __WAIT_QUEUE_HEAD_INITIALIZER(name.wait_chldexit), NULL, \
/* timeout */ SCHED_OTHER,0,0,0,0,0,0,0, \
/* timer */ { NULL, NULL, 0, 0, it_real_fn }, \
/* POSIX.1b timer */ NULL, \
/* utime */ {0,0,0,0},0, \
/* per CPU times */ {0, }, {0, }, \
/* flt */ 0,0,0,0,0,0, \
......@@ -422,7 +398,7 @@ struct task_struct {
/* fs */ &init_fs, \
/* files */ &init_files, \
/* mm */ NULL, &init_mm, \
/* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, {{0,},}, NULL, &init_task.sigqueue, 0, 0, \
/* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
}
#ifndef INIT_TASK_SIZE
......@@ -699,7 +675,6 @@ extern void exit_mm(struct task_struct *);
extern void exit_fs(struct task_struct *);
extern void exit_files(struct task_struct *);
extern void exit_sighand(struct task_struct *);
extern void exit_itimers(struct task_struct *);
extern int do_execve(char *, char **, char **, struct pt_regs *);
extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
......
......@@ -26,19 +26,6 @@ struct timespec {
*/
#define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
/* Parameters used to convert the timespec values */
#ifndef USEC_PER_SEC
#define USEC_PER_SEC (1000000L)
#endif
#ifndef NSEC_PER_SEC
#define NSEC_PER_SEC (1000000000L)
#endif
#ifndef NSEC_PER_USEC
#define NSEC_PER_USEC (1000L)
#endif
static __inline__ unsigned long
timespec_to_jiffies(struct timespec *value)
{
......@@ -47,15 +34,15 @@ timespec_to_jiffies(struct timespec *value)
if (sec >= (MAX_JIFFY_OFFSET / HZ))
return MAX_JIFFY_OFFSET;
nsec += NSEC_PER_SEC / HZ - 1;
nsec /= NSEC_PER_SEC / HZ;
nsec += 1000000000L / HZ - 1;
nsec /= 1000000000L / HZ;
return HZ * sec + nsec;
}
static __inline__ void
jiffies_to_timespec(unsigned long jiffies, struct timespec *value)
{
value->tv_nsec = (jiffies % HZ) * (NSEC_PER_SEC / HZ);
value->tv_nsec = (jiffies % HZ) * (1000000000L / HZ);
value->tv_sec = jiffies / HZ;
}
......@@ -102,23 +89,4 @@ struct itimerval {
struct timeval it_value; /* current value */
};
/*
* Data types for POSIX.1b interval timers.
*/
typedef int clockid_t;
typedef int timer_t;
/*
* The IDs of the various system clocks (for POSIX.1b interval timers).
*/
#define CLOCK_REALTIME 0
/*
* The various flags for setting POSIX.1b interval timers.
*/
#define TIMER_ABSTIME 0x01
#endif
......@@ -235,34 +235,6 @@ void exit_sighand(struct task_struct *tsk)
__exit_sighand(tsk);
}
static inline void __exit_itimers(struct task_struct *tsk)
{
struct itimer_struct *timers = tsk->posix_timers;
struct k_itimer *timr;
int i;
if (timers == NULL) return;
if (atomic_dec_and_test(&timers->count)) {
tsk->posix_timers = NULL;
for (i = 0; i < MAX_ITIMERS; i++) {
timr = timers->itimer[i];
if (timr) {
start_bh_atomic();
del_timer(&timr->it_timer);
end_bh_atomic();
kfree(timr);
}
}
kfree(timers);
}
}
void exit_itimers(struct task_struct *tsk)
{
__exit_itimers(tsk);
}
/*
* We can use these to temporarily drop into
* "lazy TLB" mode and back.
......@@ -412,7 +384,6 @@ NORET_TYPE void do_exit(long code)
__exit_files(tsk);
__exit_fs(tsk);
__exit_sighand(tsk);
__exit_itimers(tsk);
exit_thread();
tsk->state = TASK_ZOMBIE;
tsk->exit_code = code;
......
......@@ -580,24 +580,6 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
p->flags = new_flags;
}
static inline int copy_itimers(unsigned long clone_flags, struct task_struct * tsk)
{
if (clone_flags & CLONE_ITIMERS) {
atomic_inc(&tsk->posix_timers->count);
return 0;
}
tsk->posix_timers = kmalloc(sizeof(*tsk->posix_timers), GFP_KERNEL);
if (tsk->posix_timers == NULL) return -1;
spin_lock_init(&tsk->posix_timers->its_lock);
atomic_set(&tsk->posix_timers->count, 1);
memset(tsk->posix_timers->itimer, 0, sizeof(tsk->posix_timers->itimer));
return 0;
}
/*
* Ok, this is the main fork-routine. It copies the system process
* information (task[nr]) and sets up the necessary registers. It
......@@ -696,8 +678,6 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
goto bad_fork_cleanup_files;
if (copy_sighand(clone_flags, p))
goto bad_fork_cleanup_fs;
if (copy_itimers(clone_flags, p))
goto bad_fork_cleanup_itimers;
if (copy_mm(clone_flags, p))
goto bad_fork_cleanup_sighand;
retval = copy_thread(0, clone_flags, usp, p, regs);
......@@ -742,8 +722,6 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
down(&sem);
return retval;
bad_fork_cleanup_itimers:
exit_itimers(p);
bad_fork_cleanup_sighand:
exit_sighand(p);
bad_fork_cleanup_fs:
......
......@@ -9,16 +9,14 @@
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/malloc.h>
#include <linux/time.h>
#include <asm/uaccess.h>
/*
* change timeval to jiffies, trying to avoid the
* change timeval to jiffies, trying to avoid the
* most obvious overflows..
*
* The tv_*sec values are signed, but nothing seems to
* The tv_*sec values are signed, but nothing seems to
* indicate whether we really should use them as signed values
* when doing itimers. POSIX doesn't mention this (but if
* alarm() uses itimers without checking, we have to use unsigned
......@@ -170,389 +168,6 @@ asmlinkage int sys_setitimer(int which, struct itimerval *value,
return error;
if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
return -EFAULT;
return 0;
}
/* PRECONDITION:
* timr->it_lock must be locked
*/
static void timer_notify_task(struct k_itimer *timr)
{
struct siginfo info;
int ret;
if (timr->it_signal.sigev_notify == SIGEV_SIGNAL) {
/* Send signal to the process that owns this timer. */
info.si_signo = timr->it_signal.sigev_signo;
info.si_errno = 0;
info.si_code = SI_TIMER;
/* TODO: if someone has better ideas what to put in
* the next two fields...
* si_timer1 is currently used in signal.c to check
* whether a signal from this timer is already in the signal
* queue.
*/
info.si_timer1 = timr->it_id;
info.si_timer2 = 0;
info.si_value = timr->it_signal.sigev_value;
ret = send_sig_info(info.si_signo, &info, timr->it_process);
switch (ret) {
case 0: /* all's well */
timr->it_overrun = 0;
break;
case 1: /* signal from this timer was already in the queue */
timr->it_overrun++;
break;
default:
printk(KERN_WARNING "sending signal failed: %d\n", ret);
break;
}
}
}
/* This function gets called when a POSIX.1b interval timer expires. */
static void posix_timer_fn(unsigned long __data)
{
struct k_itimer *timr = (struct k_itimer *)__data;
unsigned long interval;
spin_lock(&timr->it_lock);
timer_notify_task(timr);
/* Set up the timer for the next interval (if there is one) */
if ((interval = timr->it_incr) == 0) goto out;
if (interval > (unsigned long) LONG_MAX)
interval = LONG_MAX;
timr->it_timer.expires = jiffies + interval;
add_timer(&timr->it_timer);
out:
spin_unlock(&timr->it_lock);
}
/* Find the first available slot for the new timer. */
static int timer_find_slot(struct itimer_struct *timers)
{
int i;
for (i = 0; i < MAX_ITIMERS; i++) {
if (timers->itimer[i] == NULL) return i;
}
return -1;
}
static int good_sigevent(const struct sigevent *sigev)
{
switch (sigev->sigev_notify) {
case SIGEV_NONE:
break;
case SIGEV_SIGNAL:
if ((sigev->sigev_signo <= 0) ||
(sigev->sigev_signo > SIGRTMAX))
return 0;
break;
default:
return 0;
}
return 1;
}
/* Create a POSIX.1b interval timer. */
asmlinkage int sys_timer_create(clockid_t which_clock,
struct sigevent *timer_event_spec,
timer_t *created_timer_id)
{
int error = 0;
struct k_itimer *new_timer = NULL;
struct itimer_struct *timers = current->posix_timers;
int new_timer_id;
/* Right now, we only support CLOCK_REALTIME for timers. */
if (which_clock != CLOCK_REALTIME) return -EINVAL;
new_timer = (struct k_itimer *)kmalloc(sizeof(*new_timer), GFP_KERNEL);
if (new_timer == NULL) return -EAGAIN;
spin_lock_init(&new_timer->it_lock);
new_timer->it_clock = which_clock;
new_timer->it_incr = 0;
new_timer->it_overrun = 0;
if (timer_event_spec) {
if (copy_from_user(&new_timer->it_signal, timer_event_spec,
sizeof(new_timer->it_signal))) {
error = -EFAULT;
goto out;
}
if (!good_sigevent(&new_timer->it_signal)) {
error = -EINVAL;
goto out;
}
}
else {
new_timer->it_signal.sigev_notify = SIGEV_SIGNAL;
new_timer->it_signal.sigev_signo = SIGALRM;
}
new_timer->it_interval.tv_sec = 0;
new_timer->it_interval.tv_nsec = 0;
new_timer->it_process = current;
new_timer->it_timer.next = NULL;
new_timer->it_timer.prev = NULL;
new_timer->it_timer.expires = 0;
new_timer->it_timer.data = (unsigned long)new_timer;
new_timer->it_timer.function = posix_timer_fn;
spin_lock(&timers->its_lock);
new_timer_id = timer_find_slot(timers);
if (new_timer_id == -1) {
error = -EAGAIN;
goto out;
}
new_timer->it_id = new_timer_id;
timers->itimer[new_timer_id] = new_timer;
if (timer_event_spec == NULL) {
new_timer->it_signal.sigev_value.sival_int = new_timer_id;
}
if (copy_to_user(created_timer_id, &new_timer_id, sizeof(new_timer_id))) {
error = -EFAULT;
timers->itimer[new_timer_id] = NULL;
}
spin_unlock(&timers->its_lock);
out:
if (error) {
kfree(new_timer);
}
return error;
}
/* good_timespec
*
* This function checks the elements of a timespec structure.
*
* Arguments:
* ts : Pointer to the timespec structure to check
*
* Return value:
* If a NULL pointer was passed in, or the tv_nsec field was less than 0 or
* greater than NSEC_PER_SEC, or the tv_sec field was less than 0, this
* function returns 0. Otherwise it returns 1.
*/
static int good_timespec(const struct timespec *ts)
{
if (ts == NULL) return 0;
if (ts->tv_sec < 0) return 0;
if ((ts->tv_nsec < 0) || (ts->tv_nsec >= NSEC_PER_SEC)) return 0;
return 1;
}
static inline struct k_itimer* lock_timer(struct task_struct *tsk, timer_t timer_id)
{
struct k_itimer *timr;
if ((timer_id < 0) || (timer_id >= MAX_ITIMERS)) return NULL;
spin_lock(&tsk->posix_timers->its_lock);
timr = tsk->posix_timers->itimer[timer_id];
if (timr) spin_lock(&timr->it_lock);
spin_unlock(&tsk->posix_timers->its_lock);
return timr;
}
static inline void unlock_timer(struct k_itimer *timr)
{
spin_unlock(&timr->it_lock);
}
/* Get the time remaining on a POSIX.1b interval timer. */
static void do_timer_gettime(struct k_itimer *timr,
struct itimerspec *cur_setting)
{
unsigned long expires = timr->it_timer.expires;
if (expires) expires -= jiffies;
jiffies_to_timespec(expires, &cur_setting->it_value);
cur_setting->it_interval = timr->it_interval;
}
/* Get the time remaining on a POSIX.1b interval timer. */
asmlinkage int sys_timer_gettime(timer_t timer_id, struct itimerspec *setting)
{
struct k_itimer *timr;
struct itimerspec cur_setting;
timr = lock_timer(current, timer_id);
if (!timr) return -EINVAL;
do_timer_gettime(timr, &cur_setting);
unlock_timer(timr);
copy_to_user_ret(setting, &cur_setting, sizeof(cur_setting), -EFAULT);
return 0;
}
/* Get the number of overruns of a POSIX.1b interval timer */
asmlinkage int sys_timer_getoverrun(timer_t timer_id)
{
struct k_itimer *timr;
int overrun;
timr = lock_timer(current, timer_id);
if (!timr) return -EINVAL;
overrun = timr->it_overrun;
unlock_timer(timr);
return overrun;
}
static void timer_value_abs_to_rel(struct timespec *val)
{
struct timeval tv;
struct timespec ts;
do_gettimeofday(&tv);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
/* check whether the time lies in the past */
if ((val->tv_sec < ts.tv_sec) ||
((val->tv_sec == ts.tv_sec) &&
(val->tv_nsec <= ts.tv_nsec))) {
/* expire immediately */
val->tv_sec = 0;
val->tv_nsec = 0;
}
else {
val->tv_sec -= ts.tv_sec;
val->tv_nsec -= ts.tv_nsec;
if (val->tv_nsec < 0) {
val->tv_nsec += NSEC_PER_SEC;
val->tv_sec--;
}
}
}
/* Set a POSIX.1b interval timer. */
static void do_timer_settime(struct k_itimer *timr, int flags,
struct itimerspec *new_setting,
struct itimerspec *old_setting)
{
/* disable the timer */
start_bh_atomic();
del_timer(&timr->it_timer);
end_bh_atomic();
if (old_setting) {
do_timer_gettime(timr, old_setting);
}
/* switch off the timer when it_value is zero */
if ((new_setting->it_value.tv_sec == 0) &&
(new_setting->it_value.tv_nsec == 0)) {
timr->it_incr = 0;
timr->it_timer.expires = 0;
timr->it_interval.tv_sec = 0;
timr->it_interval.tv_nsec = 0;
return;
}
timr->it_incr = timespec_to_jiffies(&new_setting->it_interval);
/* save the interval rounded to jiffies */
jiffies_to_timespec(timr->it_incr, &timr->it_interval);
if (flags & TIMER_ABSTIME) {
timer_value_abs_to_rel(&new_setting->it_value);
}
timr->it_timer.expires = timespec_to_jiffies(&new_setting->it_value) + jiffies;
/*
* For some reason the timer does not fire immediately if expires is
* equal to jiffies, so the timer callback function is called directly.
*/
if (timr->it_timer.expires == jiffies) {
posix_timer_fn((unsigned long)timr);
}
else {
add_timer(&timr->it_timer);
}
}
/* Set a POSIX.1b interval timer */
asmlinkage int sys_timer_settime(timer_t timer_id, int flags,
const struct itimerspec *new_setting,
struct itimerspec *old_setting)
{
struct k_itimer *timr;
struct itimerspec new_spec, old_spec;
int error = 0;
timr = lock_timer(current, timer_id);
if (!timr) return -EINVAL;
if (new_setting == NULL) {
error = -EINVAL;
goto out;
}
if (copy_from_user(&new_spec, new_setting, sizeof(new_spec))) {
error = -EFAULT;
goto out;
}
if ((!good_timespec(&new_spec.it_interval)) ||
(!good_timespec(&new_spec.it_value))) {
error = -EINVAL;
goto out;
}
do_timer_settime(timr, flags, &new_spec,
old_setting ? &old_spec : NULL);
if (old_setting) {
if (copy_to_user(old_setting, &old_spec, sizeof(old_spec))) {
error = -EFAULT;
}
}
out:
unlock_timer(timr);
return error;
}
/* Delete a POSIX.1b interval timer. */
asmlinkage int sys_timer_delete(timer_t timer_id)
{
struct k_itimer *timr;
timr = lock_timer(current, timer_id);
if (!timr) return -EINVAL;
start_bh_atomic();
del_timer(&timr->it_timer);
end_bh_atomic();
spin_lock(&current->posix_timers->its_lock);
kfree(timr);
current->posix_timers->itimer[timer_id] = NULL;
spin_unlock(&current->posix_timers->its_lock);
return -EFAULT;
return 0;
}
......@@ -788,8 +788,7 @@ asmlinkage void schedule(void)
atomic_inc(&oldmm->mm_count);
} else {
if (next->active_mm != mm) BUG();
if (mm != oldmm)
switch_mm(oldmm, mm, this_cpu);
switch_mm(oldmm, mm, this_cpu);
}
if (!prev->mm) {
......
......@@ -132,7 +132,17 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
/* Collect the siginfo appropriate to this signal. */
if (sig < SIGRTMIN) {
*info = current->nrt_info[sig];
/* XXX: As an extension, support queueing exactly
one non-rt signal if SA_SIGINFO is set, so that
we can get more detailed information about the
cause of the signal. */
/* Deciding not to init these couple of fields is
more expensive that just initializing them. */
info->si_signo = sig;
info->si_errno = 0;
info->si_code = 0;
info->si_pid = 0;
info->si_uid = 0;
} else {
struct signal_queue *q, **pp;
pp = &current->sigqueue;
......@@ -175,6 +185,8 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
sigdelset(&current->signal, sig);
recalc_sigpending(current);
/* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER,
we need to xchg out the timer overrun values. */
} else {
/* XXX: Once CLONE_PID is in to join those "threads" that are
part of the same "process", look for signals sent to the
......@@ -235,29 +247,6 @@ static int ignored_signal(int sig, struct task_struct *t)
return 1;
}
static void set_siginfo(siginfo_t *dst, const siginfo_t *src, int sig)
{
switch ((unsigned long)src) {
case 0:
dst->si_signo = sig;
dst->si_errno = 0;
dst->si_code = SI_USER;
dst->si_pid = current->pid;
dst->si_uid = current->uid;
break;
case 1:
dst->si_signo = sig;
dst->si_errno = 0;
dst->si_code = SI_KERNEL;
dst->si_pid = 0;
dst->si_uid = 0;
break;
default:
*dst = *src;
break;
}
}
int
send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
{
......@@ -317,10 +306,12 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
if (sig < SIGRTMIN) {
/* Non-real-time signals are not queued. */
/* XXX: As an extension, support queueing exactly one
non-rt signal if SA_SIGINFO is set, so that we can
get more detailed information about the cause of
the signal. */
if (sigismember(&t->signal, sig))
goto out;
set_siginfo(&t->nrt_info[sig], info, sig);
} else {
/* Real-time signals must be queued if sent by sigqueue, or
some other real-time mechanism. It is implementation
......@@ -332,21 +323,6 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
struct signal_queue *q = 0;
/* In case of a POSIX timer generated signal you must check
if a signal from this timer is already in the queue */
if (info && (info->si_code == SI_TIMER)) {
for (q = t->sigqueue; q; q = q->next) {
if ((q->info.si_code == SI_TIMER) &&
(q->info.si_timer1 == info->si_timer1)) {
/* this special value (1) is recognized
only by posix_timer_fn() in
itimer.c */
ret = 1;
goto out;
}
}
}
if (atomic_read(&nr_queued_signals) < max_queued_signals) {
q = (struct signal_queue *)
kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
......@@ -357,7 +333,25 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
q->next = NULL;
*t->sigqueue_tail = q;
t->sigqueue_tail = &q->next;
set_siginfo(&q->info, info, sig);
switch ((unsigned long) info) {
case 0:
q->info.si_signo = sig;
q->info.si_errno = 0;
q->info.si_code = SI_USER;
q->info.si_pid = current->pid;
q->info.si_uid = current->uid;
break;
case 1:
q->info.si_signo = sig;
q->info.si_errno = 0;
q->info.si_code = SI_KERNEL;
q->info.si_pid = 0;
q->info.si_uid = 0;
break;
default:
q->info = *info;
break;
}
} else {
/* If this was sent by a rt mechanism, try again. */
if (info->si_code < 0) {
......
......@@ -414,57 +414,3 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
ret = do_adjtimex(&txc);
return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
}
/* POSIX.1b clock functions */
asmlinkage int sys_clock_gettime(clockid_t clock_id, struct timespec *ts)
{
struct timespec kts;
struct timeval ktv;
if (clock_id != CLOCK_REALTIME) return -EINVAL;
if (ts == NULL) return 0;
do_gettimeofday(&ktv);
kts.tv_sec = ktv.tv_sec;
kts.tv_nsec = ktv.tv_usec * NSEC_PER_USEC;
if (copy_to_user(ts, &kts, sizeof(kts))) return -EFAULT;
return 0;
}
asmlinkage int sys_clock_settime(clockid_t clock_id,
const struct timespec *ts)
{
struct timespec new_ts;
struct timeval tv;
if (clock_id != CLOCK_REALTIME) return -EINVAL;
if (ts == NULL) return 0;
if (copy_from_user(&new_ts, ts, sizeof(*ts))) return -EFAULT;
tv.tv_sec = new_ts.tv_sec;
tv.tv_usec = new_ts.tv_nsec / NSEC_PER_USEC;
return do_sys_settimeofday(&tv, NULL);
}
asmlinkage int sys_clock_getres(clockid_t clock_id,
struct timespec *res)
{
struct timespec kres;
if (clock_id != CLOCK_REALTIME) return -EINVAL;
if (res == NULL) return 0;
kres.tv_sec = 0;
kres.tv_nsec = NSEC_PER_SEC / HZ;
if (copy_to_user(res, &kres, sizeof(kres))) return -EFAULT;
return 0;
}
......@@ -824,6 +824,7 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
return 1;
bad_wp_page:
spin_unlock(&tsk->mm->page_table_lock);
printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
return -1;
}
......
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