Commit 55b19867 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.2

parent 02ef4085
......@@ -661,7 +661,7 @@ N: Richard E. Gooch
E: rgooch@atnf.csiro.au
D: parent process death signal to children
D: prctl() syscall
D: /proc/mtrr support to manipulate MTRRs on Pentium Pro's
D: /proc/mtrr support to manipulate MTRRs on Intel P6 family
S: CSIRO Australia Telescope National Facility
S: P.O. Box 76, Epping
S: New South Wales, 2121
......@@ -759,6 +759,13 @@ S: 77 Clarence Mews
S: London SE16 1GD
S: United Kingdom
N: Bart Hartgers
E: bart@etpmod.phys.tue.nl
D: MTRR emulation with Centaur MCRs
S: Gen Stedmanstraat 212
S: 5623 HZ Eindhoven
S: The Netherlands
N: Kai Harrekilde-Petersen
E: khp@dolphinics.no
D: Original author of the ftape-HOWTO, i82078 fdc detection code.
......
......@@ -8855,6 +8855,9 @@ CONFIG_MTRR
The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
MTRRs. These are supported.
The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
are supported.
Saying Y here also fixes a problem with buggy SMP BIOSes which only
set the MTRRs for the boot CPU and not the secondary CPUs. This can
......
This diff is collapsed.
Video Mode Selection Support 2.11
(c) 1995--1997 Martin Mares, <mj@k332.feld.cvut.cz>
Video Mode Selection Support 2.13
(c) 1995--1999 Martin Mares, <mj@ucw.cz>
--------------------------------------------------------------------------------
1. Intro
......@@ -9,6 +9,11 @@ allows the use of various special video modes supported by the video BIOS. Due
to usage of the BIOS, the selection is limited to boot time (before the
kernel decompression starts) and works only on 80X86 machines.
** Short intro for the impatient: Just use vga=ask for the first time,
** enter `scan' on the video mode prompt, pick the mode you want to use,
** remember its mode ID (the four-digit hexadecimal number) and then
** set the vga parameter to this number (converted to decimal first).
The video mode to be used is selected by a kernel parameter which can be
specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..."
option of LILO (or some other boot loader you use) or by the "vidmode" utility
......@@ -268,3 +273,4 @@ force setting of the correct mode.
- Removed the doc section describing adding of new probing
functions as I try to get rid of _all_ hardware probing here.
2.12 (25-May-98)- Added support for VESA frame buffer graphics.
2.13 (14-May-99)- Minor documentation fixes.
VERSION = 2
PATCHLEVEL = 3
SUBLEVEL = 1
SUBLEVEL = 2
EXTRAVERSION =
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
......
......@@ -52,6 +52,7 @@ EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(screen_info);
EXPORT_SYMBOL(perf_irq);
......
/*
* kernel/fpreg.c
* arch/alpha/kernel/fpreg.c
*
* (C) Copyright 1998 Linus Torvalds
*/
#ifdef __alpha_cix__
#if defined(__alpha_cix__) || defined(__alpha_fix__)
#define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val));
#else
#define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val));
......@@ -52,7 +52,7 @@ alpha_read_fp_reg (unsigned long reg)
return val;
}
#ifdef __alpha_cix__
#if defined(__alpha_cix__) || defined(__alpha_fix__)
#define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val));
#else
#define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val));
......
......@@ -32,24 +32,26 @@ __start:
#ifdef __SMP__
.align 3
.globl __start_cpu
.ent __start_cpu
/* On entry here from SRM console, the HWPCB of this processor
has been loaded, and $27 contains the task pointer */
__start_cpu:
.prologue 0
/* First order of business, load the GP */
br $26,1f
1: ldgp $29,0($26)
/* We need to get current loaded up with our first task... */
mov $27,$8
/* Set FEN */
lda $16,1($31)
call_pal PAL_wrfen
/* ... and then we can start the processor. */
jsr $26,start_secondary
.globl __smp_callin
.ent __smp_callin
/* On entry here from SRM console, the HWPCB of the per-cpu
slot for this processor has been loaded. We've arranged
for the UNIQUE value for this process to contain the PCBB
of the target idle task. */
__smp_callin:
.prologue 1
ldgp $29,0($27) # First order of business, load the GP.
call_pal PAL_rduniq # Grab the target PCBB.
mov $0,$16 # Install it.
call_pal PAL_swpctx
lda $8,0x3fff # Find "current".
bic $30,$8,$8
jsr $26,smp_callin
call_pal PAL_halt
.end __start_cpu
.end __smp_callin
#endif /* __SMP__ */
.align 3
......
......@@ -192,7 +192,7 @@ unmask_irq(unsigned long irq)
}
void
disable_irq(unsigned int irq_nr)
disable_irq_nosync(unsigned int irq_nr)
{
unsigned long flags;
......@@ -201,6 +201,14 @@ disable_irq(unsigned int irq_nr)
restore_flags(flags);
}
void
disable_irq(unsigned int irq_nr)
{
/* This works non-SMP, and SMP until we write code to distribute
interrupts to more that cpu 0. */
disable_irq_nosync(irq_nr);
}
void
enable_irq(unsigned int irq_nr)
{
......
......@@ -75,33 +75,46 @@ sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
return 0;
}
static void __attribute__((noreturn))
do_cpu_idle(void)
#ifdef __SMP__
void
cpu_idle(void *unused)
{
/* An endless idle loop with no priority at all. */
current->priority = 0;
current->counter = -100;
while (1) {
check_pgt_cache();
run_task_queue(&tq_scheduler);
current->counter = 0;
schedule();
/* FIXME -- EV6 and LCA45 know how to power down
the CPU. */
/* Although we are an idle CPU, we do not want to
get into the scheduler unnecessarily. */
if (current->need_resched) {
schedule();
check_pgt_cache();
}
}
}
#ifdef __SMP__
void
cpu_idle(void *unused)
{
do_cpu_idle();
}
#endif
asmlinkage int
sys_idle(void)
{
if (current->pid == 0)
do_cpu_idle();
return -EPERM;
if (current->pid != 0)
return -EPERM;
/* An endless idle loop with no priority at all. */
current->priority = 0;
current->counter = -100;
init_idle();
while (1) {
/* FIXME -- EV6 and LCA45 know how to power down
the CPU. */
schedule();
check_pgt_cache();
}
}
void
......
......@@ -151,6 +151,8 @@ extern unsigned long srm_hae;
extern void setup_smp(void);
extern int smp_info(char *buffer);
extern void handle_ipi(struct pt_regs *);
extern void smp_percpu_timer_interrupt(struct pt_regs *);
extern int smp_boot_cpuid;
/* bios32.c */
extern void reset_for_srm(void);
......@@ -178,7 +180,7 @@ extern unsigned long alpha_read_fp_reg (unsigned long reg);
extern void wrmces(unsigned long mces);
extern void cserve_ena(unsigned long);
extern void cserve_dis(unsigned long);
extern void __start_cpu(unsigned long);
extern void __smp_callin(void);
/* entry.S */
extern void entArith(void);
......
......@@ -24,6 +24,9 @@
#include <asm/sigcontext.h>
#include <asm/ucontext.h>
#include "proto.h"
#define DEBUG_SIG 0
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
......
This diff is collapsed.
......@@ -42,6 +42,9 @@
#include "proto.h"
#include "irq.h"
extern rwlock_t xtime_lock;
extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
static int set_rtc_mmss(unsigned long);
......@@ -86,15 +89,15 @@ void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
long nticks;
#ifdef __SMP__
extern void smp_percpu_timer_interrupt(struct pt_regs *);
extern unsigned int boot_cpu_id;
/* when SMP, do this for *all* CPUs,
but only do the rest for the boot CPU */
/* When SMP, do this for *all* CPUs, but only do the rest for
the boot CPU. */
smp_percpu_timer_interrupt(regs);
if (smp_processor_id() != boot_cpu_id)
return;
if (smp_processor_id() != smp_boot_cpuid)
return;
#endif
write_lock(&xtime_lock);
/*
* Calculate how many ticks have passed since the last update,
* including any previous partial leftover. Save any resulting
......@@ -124,6 +127,8 @@ void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
int tmp = set_rtc_mmss(xtime.tv_sec);
state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0);
}
write_unlock(&xtime_lock);
}
/*
......@@ -226,7 +231,8 @@ time_init(void)
{
void (*irq_handler)(int, void *, struct pt_regs *);
unsigned int year, mon, day, hour, min, sec, cc1, cc2;
unsigned long cycle_freq, diff, one_percent;
unsigned long cycle_freq, one_percent;
long diff;
/*
* The Linux interpretation of the CMOS clock register contents:
......@@ -242,7 +248,7 @@ time_init(void)
if (!est_cycle_freq) {
/* Sometimes the hwrpb->cycle_freq value is bogus.
Go another round to check up on it and see. */
Go another round to check up on it and see. */
do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
cc2 = rpcc();
......@@ -279,8 +285,7 @@ time_init(void)
mon = CMOS_READ(RTC_MONTH);
year = CMOS_READ(RTC_YEAR);
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BCD_TO_BIN(sec);
BCD_TO_BIN(min);
BCD_TO_BIN(hour);
......@@ -328,18 +333,24 @@ time_init(void)
void
do_gettimeofday(struct timeval *tv)
{
unsigned long flags, delta_cycles, delta_usec;
unsigned long sec, usec;
__u32 now;
extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
unsigned long sec, usec, lost, flags;
unsigned long delta_cycles, delta_usec, partial_tick;
now = rpcc();
save_and_cli(flags);
read_lock_irqsave(&xtime_lock, flags);
delta_cycles = rpcc() - state.last_time;
sec = xtime.tv_sec;
usec = xtime.tv_usec;
delta_cycles = now - state.last_time;
restore_flags(flags);
partial_tick = state.partial_tick;
lost = lost_ticks;
read_unlock_irqrestore(&xtime_lock, flags);
#ifdef __SMP__
/* Until and unless we figure out how to get cpu cycle counters
in sync and keep them there, we can't use the rpcc tricks. */
delta_usec = lost * (1000000 / HZ);
#else
/*
* usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
* = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks)
......@@ -354,13 +365,10 @@ do_gettimeofday(struct timeval *tv)
*/
delta_usec = (delta_cycles * state.scaled_ticks_per_cycle
+ state.partial_tick
+ (lost_ticks << FIX_SHIFT) ) * 15625;
+ partial_tick
+ (lost << FIX_SHIFT)) * 15625;
delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
/* the 'lost_tics' term above implements this:
* delta_usec += lost_ticks * (1000000 / HZ);
*/
#endif
usec += delta_usec;
if (usec >= 1000000) {
......@@ -375,13 +383,41 @@ do_gettimeofday(struct timeval *tv)
void
do_settimeofday(struct timeval *tv)
{
cli();
xtime = *tv;
unsigned long delta_usec;
long sec, usec;
write_lock_irq(&xtime_lock);
/* The offset that is added into time in do_gettimeofday above
must be subtracted out here to keep a coherent view of the
time. Without this, a full-tick error is possible. */
#ifdef __SMP__
delta_usec = lost_ticks * (1000000 / HZ);
#else
delta_usec = rpcc() - state.last_time;
delta_usec = (delta_usec * state.scaled_ticks_per_cycle
+ state.partial_tick
+ (lost_ticks << FIX_SHIFT)) * 15625;
delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
#endif
sec = tv->tv_sec;
usec = tv->tv_usec;
usec -= delta_usec;
if (usec < 0) {
usec += 1000000;
sec -= 1;
}
xtime.tv_sec = sec;
xtime.tv_usec = usec;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
sti();
write_unlock_irq(&xtime_lock);
}
......
/*
* kernel/traps.c
* arch/alpha/kernel/traps.c
*
* (C) Copyright 1994 Linus Torvalds
*/
......@@ -95,6 +95,9 @@ die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15)
{
if (regs->ps & 8)
return;
#ifdef __SMP__
printk("CPU %d ", hard_smp_processor_id());
#endif
printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
dik_show_regs(regs, r9_15);
dik_show_code((unsigned int *)regs->pc);
......@@ -128,8 +131,8 @@ do_entArith(unsigned long summary, unsigned long write_mask,
if (summary & 1) {
/* Software-completion summary bit is set, so try to
emulate the instruction. */
if (implver() == IMPLVER_EV6) {
/* Whee! EV6 has precice exceptions. */
if (!amask(AMASK_PRECISE_TRAP)) {
/* 21264 (except pass 1) has precise exceptions. */
if (alpha_fp_emul(regs.pc - 4))
return;
} else {
......@@ -138,14 +141,12 @@ do_entArith(unsigned long summary, unsigned long write_mask,
}
}
lock_kernel();
#if 0
printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
current->comm, regs.pc, summary, write_mask);
#endif
die_if_kernel("Arithmetic fault", &regs, 0, 0);
send_sig(SIGFPE, current, 1);
unlock_kernel();
}
asmlinkage void
......@@ -235,10 +236,8 @@ do_entDbg(unsigned long type, unsigned long a1,
unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs)
{
lock_kernel();
die_if_kernel("Instruction fault", &regs, type, 0);
force_sig(SIGILL, current);
unlock_kernel();
}
......@@ -453,10 +452,8 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg,
unsigned long newpc;
newpc = fixup_exception(una_reg, fixup, pc);
lock_kernel();
printk("Forwarding unaligned exception at %lx (%lx)\n",
pc, newpc);
unlock_kernel();
(&regs)->pc = newpc;
return;
......@@ -610,11 +607,9 @@ do_entUnaUser(void * va, unsigned long opcode,
cnt = 0;
}
if (++cnt < 5) {
lock_kernel();
printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
current->comm, current->pid,
regs->pc - 4, va, opcode, reg);
unlock_kernel();
}
last_time = jiffies;
}
......@@ -868,16 +863,12 @@ do_entUnaUser(void * va, unsigned long opcode,
give_sigsegv:
regs->pc -= 4; /* make pc point to faulting insn */
lock_kernel();
send_sig(SIGSEGV, current, 1);
unlock_kernel();
return;
give_sigbus:
regs->pc -= 4;
lock_kernel();
send_sig(SIGBUS, current, 1);
unlock_kernel();
return;
}
......
......@@ -256,26 +256,6 @@ paging_init(unsigned long start_mem, unsigned long end_mem)
return start_mem;
}
#ifdef __SMP__
/*
* paging_init_secondary(), called ONLY by secondary CPUs,
* sets up current->tss contents appropriately and does a load_PCB.
* note that current should be pointing at the idle thread task struct
* for this CPU.
*/
void
paging_init_secondary(void)
{
current->tss.ptbr = init_task.tss.ptbr;
current->tss.pal_flags = 1;
current->tss.flags = 0;
load_PCB(&current->tss);
tbia();
return;
}
#endif /* __SMP__ */
#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
void
srm_paging_stop (void)
......
!
! Display adapter & video mode setup, version 2.12 (25-May-98)
! Display adapter & video mode setup, version 2.13 (14-May-99)
!
! Copyright (C) 1995 -- 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
! Copyright (C) 1995 -- 1999 Martin Mares <mj@ucw.cz>
! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
!
! For further information, look at Documentation/svga.txt.
!
#include <linux/config.h> /* for CONFIG_VIDEO_* */
! Enable autodetection of SVGA adapters and modes. If you really need this
! feature, drop me a mail as I think of removing it some day...
! feature, drop me a mail as I think of removing it some day. You can
! always enter `scan' to get the video mode table and then use the real
! video mode numbers (those 4-digit hexadecimal numbers, NOT the menu
! item numbers) which don't rely on any autodetection.
#undef CONFIG_VIDEO_SVGA
! Enable autodetection of VESA modes
......@@ -1939,7 +1944,7 @@ unknt: .ascii "Unknown mode ID. Try again."
badmdt: .ascii "You passed an undefined mode number."
db 0x0d, 0x0a, 0
vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
.ascii "report to <mj@k332.feld.cvut.cz>."
.ascii "report to <mj@ucw.cz>."
db 0x0d, 0x0a, 0
old_name: .ascii "CGA/MDA/HGA"
db 0
......
......@@ -305,6 +305,7 @@ CONFIG_USB_UHCI=y
CONFIG_USB_MOUSE=y
CONFIG_USB_KBD=y
# CONFIG_USB_AUDIO is not set
# CONFIG_USB_ACM is not set
#
# Filesystems
......
......@@ -314,7 +314,7 @@ static int got_clock_diff = 0;
static int debug = 0;
static int apm_disabled = 0;
static struct wait_queue * process_list = NULL;
static DECLARE_WAIT_QUEUE_HEAD(process_list);
static struct apm_bios_struct * user_list = NULL;
static struct timer_list apm_timer;
......
This diff is collapsed.
......@@ -9,6 +9,9 @@
* Force Cyrix 6x86(MX) and M II processors to report MTRR capability
* and fix against Cyrix "coma bug" by
* Zoltan Boszormenyi <zboszor@mol.hu> February 1999.
*
* Force Centaur C6 processors to report MTRR capability.
* Bart Hartgers <bart@etpmod.phys.tue.nl>, May 199.
*/
/*
......@@ -861,6 +864,8 @@ __initfunc(void print_cpu_info(struct cpuinfo_x86 *c))
/* lv|=(1<<6); - may help too if the board can cope */
printk("now 0x%X", lv);
wrmsr(0x107, lv, hv);
/* Emulate MTRRs using Centaur's MCR. */
c->x86_capability |= X86_FEATURE_MTRR;
}
printk("\n");
}
......
......@@ -370,7 +370,6 @@ __initfunc(unsigned int pci_init_hpt343 (struct pci_dev *dev, const char *name))
inb(hpt343IoBase + 0x0011));
#endif
pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x80);
if (cmd & PCI_COMMAND_MEMORY) {
if (dev->rom_address) {
pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
......
......@@ -240,7 +240,6 @@ __initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const
dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
pci_write_config_byte(dev, 0x80, 0x80);
if (!(pcicmd & PCI_COMMAND_MEMORY))
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
}
......
......@@ -51,14 +51,8 @@ extern void mda_console_init(void);
#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
extern void adbdev_init(void);
#endif
#ifdef CONFIG_USB_UHCI
int uhci_init(void);
#endif
#ifdef CONFIG_USB_OHCI
int ohci_init(void);
#endif
#ifdef CONFIG_USB_OHCI_HCD
int ohci_hcd_init(void);
#ifdef CONFIG_USB
extern void usb_init(void);
#endif
static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
......@@ -609,15 +603,7 @@ __initfunc(int chr_dev_init(void))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
rand_initialize();
#ifdef CONFIG_USB
#ifdef CONFIG_USB_UHCI
uhci_init();
#endif
#ifdef CONFIG_USB_OHCI
ohci_init();
#endif
#ifdef CONFIG_USB_OHCI_HCD
ohci_hcd_init();
#endif
usb_init();
#endif
#if defined (CONFIG_FB)
fbmem_init();
......
......@@ -40,13 +40,12 @@
#include <linux/errno.h>
#include <linux/hdreg.h>
#include <linux/malloc.h>
#include <linux/ide.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include "../block/ide.h"
#include "scsi.h"
#include "hosts.h"
#include "sd.h"
......
......@@ -1334,13 +1334,13 @@ static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved)
return sdp->headfp;
}
sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0);
if (sfp) {
memset(sfp, 0, sizeof(Sg_fd));
sfp->my_mem_src = SG_HEAP_KMAL;
}
else
return NULL;
if (!sfp)
return NULL;
memset(sfp, 0, sizeof(Sg_fd));
sfp->my_mem_src = SG_HEAP_KMAL;
init_waitqueue_head(&sfp->read_wait);
sfp->timeout = SG_DEFAULT_TIMEOUT;
sfp->force_packid = SG_DEF_FORCE_PACK_ID;
sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
......
......@@ -122,11 +122,9 @@ int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned bufl
if (!quiet)
printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
"REQUEST.\n", target);
if ((SCpnt->sense_buffer[12] == 0x20 ||
SCpnt->sense_buffer[12] == 0x24) &&
if (SCpnt->sense_buffer[12] == 0x20 &&
SCpnt->sense_buffer[13] == 0x00) {
/* sense: Invalid command operation code */
/* or Invalid field in cdb */
err = -EDRIVE_CANT_DO_THIS;
} else {
err = -EINVAL;
......
......@@ -234,9 +234,9 @@ struct audio_operations
int parent_dev; /* 0 -> no parent, 1 to n -> parent=parent_dev+1 */
/* fields formerly in dmabuf.c */
struct wait_queue *in_sleeper;
struct wait_queue *out_sleeper;
struct wait_queue *poll_sleeper;
wait_queue_head_t in_sleeper;
wait_queue_head_t out_sleeper;
wait_queue_head_t poll_sleeper;
/* fields formerly in audio.c */
int audio_mode;
......
......@@ -23,6 +23,7 @@ if [ ! "$CONFIG_USB" = "n" ]; then
bool 'USB mouse support' CONFIG_USB_MOUSE
bool 'USB keyboard support' CONFIG_USB_KBD
bool 'USB audio parsing support' CONFIG_USB_AUDIO
bool 'USB Abstract Control Model support' CONFIG_USB_ACM
fi
endmenu
......@@ -24,6 +24,10 @@ ifeq ($(CONFIG_USB_MOUSE),y)
USBX_OBJS += mouse.o
endif
ifeq ($(CONFIG_USB_ACM),y)
USBX_OBJS += acm.o
endif
ifeq ($(CONFIG_USB_KBD),y)
USBX_OBJS += keyboard.o keymap.o
endif
......
/*
* USB Abstract Control Model based on Brad Keryan's USB busmouse driver
*
* Armin Fuerst 5/8/1999
*
* version 0.0: Driver sets up configuration, setus up data pipes, opens misc
* device. No actual data transfer is done, since we don't have bulk transfer,
* yet. Purely skeleton for now.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/malloc.h>
#include <asm/spinlock.h>
#include "usb.h"
#define USB_ACM_MINOR 32
struct acm_state {
int present; /* this acm is plugged in */
int active; /* someone is has this acm's device open */
struct usb_device *dev;
unsigned int readpipe,writepipe;
};
static struct acm_state static_acm_state;
spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED;
static int acm_irq(int state, void *__buffer, void *dev_id)
{
/*
signed char *data = __buffer;
struct acm_state *acm = &static_acm_state;
if(!acm->active)
return 1;
*/
/*We should so something useful here*/
printk("ACM_USB_IRQ\n");
return 1;
}
static int release_acm(struct inode * inode, struct file * file)
{
struct acm_state *acm = &static_acm_state;
printk("ACM_FILE_RELEASE\n");
// fasync_acm(-1, file, 0);
if (--acm->active)
return 0;
return 0;
}
static int open_acm(struct inode * inode, struct file * file)
{
struct acm_state *acm = &static_acm_state;
printk("USB_FILE_OPEN\n");
if (!acm->present)
return -EINVAL;
if (acm->active++)
return 0;
return 0;
}
static ssize_t write_acm(struct file * file,
const char * buffer, size_t count, loff_t *ppos)
{
char * buffer="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
struct acm_state *acm = &static_acm_state;
printk("USB_FILE_WRITE\n");
printk("writing:>%s<\n",buffer);
acm->dev->bus->op->bulk_msg(acm->dev,acm->writepipe,buffer, 26);
printk("done:>%s<\n",buffer);
printk("reading:>%s<\n",buffer);
acm->dev->bus->op->bulk_msg(acm->dev,acm->readpipe,buffer, 26);
printk("done:>%s<\n",buffer);
return -EINVAL;
}
static ssize_t read_acm(struct file * file, char * buffer, size_t count, loff_t *ppos)
{
printk("USB_FILE_READ\n");
return -EINVAL;
}
struct file_operations usb_acm_fops = {
NULL, /* acm_seek */
read_acm,
write_acm,
NULL, /* acm_readdir */
NULL, /* acm_poll */
NULL, /* acm_ioctl */
NULL, /* acm_mmap */
open_acm,
NULL, /* flush */
release_acm,
NULL,
NULL, /*fasync*/
};
static struct miscdevice usb_acm = {
USB_ACM_MINOR, "USB ACM", &usb_acm_fops
};
static int acm_probe(struct usb_device *dev)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
struct acm_state *acm = &static_acm_state;
int cfgnum;
/* Only use CDC */
if (dev->descriptor.bDeviceClass != 2 ||
dev->descriptor.bDeviceSubClass != 0 ||
dev->descriptor.bDeviceProtocol != 0)
return -1;
/*Now scan all configs for a ACM configuration*/
for (cfgnum=0;cfgnum<dev->descriptor.bNumConfigurations;cfgnum++) {
/* The first one should be Communications interface? */
interface = &dev->config[cfgnum].interface[0];
if (interface->bInterfaceClass != 2 ||
interface->bInterfaceSubClass != 2 ||
interface->bInterfaceProtocol != 1 ||
interface->bNumEndpoints != 1)
continue;
/*Which uses an interrupt input */
endpoint = &interface->endpoint[0];
if ((endpoint->bEndpointAddress & 0x80) != 0x80 ||
(endpoint->bmAttributes & 3) != 3)
continue;
/* The second one should be a Data interface? */
interface = &dev->config[cfgnum].interface[1];
if (interface->bInterfaceClass != 10 ||
interface->bInterfaceSubClass != 0 ||
interface->bInterfaceProtocol != 0 ||
interface->bNumEndpoints != 2)
continue;
/*With a bulk input */
endpoint = &interface->endpoint[0];
if ((endpoint->bEndpointAddress & 0x80) != 0x80 ||
(endpoint->bmAttributes & 3) != 2)
continue;
/*And a bulk output */
endpoint = &interface->endpoint[1];
if ((endpoint->bEndpointAddress & 0x80) == 0x80 ||
(endpoint->bmAttributes & 3) != 2)
continue;
printk("USB ACM found\n");
usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue);
acm->dev=dev;
acm->readpipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[0]);
acm->writepipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[1]);
usb_request_irq(dev, usb_rcvctrlpipe(dev,&dev->config[cfgnum].interface[0].endpoint[0]), acm_irq, endpoint->bInterval, NULL);
acm->present = 1;
return 0;
}
return -1;
}
static void acm_disconnect(struct usb_device *dev)
{
struct acm_state *acm = &static_acm_state;
/* this might need work */
acm->present = 0;
}
static struct usb_driver acm_driver = {
"acm",
acm_probe,
acm_disconnect,
{ NULL, NULL }
};
int usb_acm_init(void)
{
struct acm_state *acm = &static_acm_state;
misc_register(&usb_acm);
acm->present = acm->active = 0;
usb_register(&acm_driver);
printk(KERN_INFO "USB ACM registered.\n");
return 0;
}
#if 0
int init_module(void)
{
return usb_acm_init();
}
void cleanup_module(void)
{
/* this, too, probably needs work */
usb_deregister(&acm_driver);
misc_deregister(&usb_acm);
}
#endif
......@@ -1246,7 +1246,7 @@ static struct usb_driver cpia_driver = {
/*
* This should be a separate module.
*/
int cpia_init(void)
int usb_cpia_init(void)
{
usb_register(&cpia_driver);
......
......@@ -394,7 +394,7 @@ static struct usb_driver hub_driver = {
/*
* This should be a separate module.
*/
int hub_init(void)
int usb_hub_init(void)
{
int pid;
......
......@@ -2,5 +2,6 @@ int bp_mouse_init(void);
int usb_kbd_init(void);
int usb_audio_init(void);
int hub_init(void);
int usb_acm_init(void);
void hub_cleanup(void);
void usb_mouse_cleanup(void);
......@@ -234,10 +234,14 @@ static struct usb_device *sohci_usb_allocate(struct usb_device *parent) {
return usb_dev;
}
/* FIXME! */
#define sohci_bulk_msg NULL
struct usb_operations sohci_device_operations = {
sohci_usb_allocate,
sohci_usb_deallocate,
sohci_control_msg,
sohci_bulk_msg,
sohci_request_irq,
};
......@@ -1429,7 +1433,6 @@ static int handle_apm_event(apm_event_t event)
#endif
int usb_mouse_init(void);
#ifdef MODULE
void cleanup_module(void)
......@@ -1460,16 +1463,6 @@ int ohci_hcd_init(void)
if (retval < 0) break;
#ifdef CONFIG_USB_MOUSE
usb_mouse_init();
#endif
#ifdef CONFIG_USB_KBD
usb_kbd_init();
#endif
hub_init();
#ifdef CONFIG_USB_AUDIO
usb_audio_init();
#endif
#ifdef CONFIG_APM
apm_register_callback(&handle_apm_event);
#endif
......@@ -1478,12 +1471,3 @@ int ohci_hcd_init(void)
}
return retval;
}
void cleanup_drivers(void)
{
hub_cleanup();
#ifdef CONFIG_USB_MOUSE
usb_mouse_cleanup();
#endif
}
......@@ -429,7 +429,7 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)),
TOGGLE_AUTO,
OHCI_TD_ROUND,
dev->data, DATA_BUF_LEN,
&dev->data, DATA_BUF_LEN,
dev_id, handler);
/*
* TODO: be aware that OHCI won't advance out of the 4kb
......@@ -728,6 +728,8 @@ static int ohci_usb_deallocate(struct usb_device *usb_dev)
return 0;
}
/* FIXME! */
#define ohci_bulk_msg NULL
/*
* functions for the generic USB driver
......@@ -736,6 +738,7 @@ struct usb_operations ohci_device_operations = {
ohci_usb_allocate,
ohci_usb_deallocate,
ohci_control_msg,
ohci_bulk_msg,
ohci_request_irq,
};
......@@ -819,6 +822,18 @@ static int start_hc(struct ohci *ohci)
/* Enable control lists */
writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control);
/* Force global power enable -gal@cs.uni-magdeburg.de */
/*
* This turns on global power switching for all the ports
* and tells the HC that all of the ports should be powered on
* all of the time.
*
* TODO: This could be battery draining for laptops.. We
* should implement power switching.
*/
writel_set( OHCI_ROOT_A_NPS, &ohci->regs->roothub.a );
writel_mask( ~((__u32)OHCI_ROOT_A_PSM), &ohci->regs->roothub.a );
/* Turn on power to the root hub ports (thanks Roman!) */
writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status );
......@@ -1262,23 +1277,23 @@ static struct ohci *alloc_ohci(void* mem_base)
* Initialize the polling table to call interrupts at the
* intended intervals.
*/
dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]);
dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_1]);
for (i = 1; i < NUM_INTS; i++) {
if (i & 1)
if (i & 16)
dev->hcca->int_table[i] =
virt_to_bus(&dev->ed[ED_INT_32]);
if (i & 8)
dev->hcca->int_table[i] =
virt_to_bus(&dev->ed[ED_INT_16]);
else if (i & 2)
if (i & 4)
dev->hcca->int_table[i] =
virt_to_bus(&dev->ed[ED_INT_8]);
else if (i & 4)
if (i & 2)
dev->hcca->int_table[i] =
virt_to_bus(&dev->ed[ED_INT_4]);
else if (i & 8)
if (i & 1)
dev->hcca->int_table[i] =
virt_to_bus(&dev->ed[ED_INT_2]);
else if (i & 16)
dev->hcca->int_table[i] =
virt_to_bus(&dev->ed[ED_INT_1]);
}
/*
......@@ -1470,9 +1485,12 @@ static int handle_apm_event(apm_event_t event)
#ifdef OHCI_TIMER
/*
* Inspired by Iñaky's driver. This function is a timer routine that
* is called OHCI_TIMER_FREQ times per second. It polls the root hub
* for status changes as on my system things are acting a bit odd at
* the moment..
* is called every OHCI_TIMER_FREQ ms. It polls the root hub for
* status changes as on my system the RHSC interrupt just doesn't
* play well with others.. (so RHSC is turned off by default in this
* driver)
* [my controller is a "SiS 7001 USB (rev 16)"]
* -greg
*/
static void ohci_timer_func (unsigned long ohci_ptr)
{
......@@ -1480,8 +1498,9 @@ static void ohci_timer_func (unsigned long ohci_ptr)
ohci_root_hub_events(ohci);
/* press the snooze button... */
mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ));
/* set the next timer */
mod_timer(&ohci_timer, jiffies + ((OHCI_TIMER_FREQ*HZ)/1000));
} /* ohci_timer_func() */
#endif
......@@ -1507,9 +1526,10 @@ static int found_ohci(int irq, void* mem_base)
#ifdef OHCI_TIMER
init_timer(&ohci_timer);
ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ);
ohci_timer.expires = jiffies + ((OHCI_TIMER_FREQ*HZ)/1000);
ohci_timer.data = (unsigned long)ohci;
ohci_timer.function = ohci_timer_func;
add_timer(&ohci_timer);
#endif
retval = -EBUSY;
......@@ -1644,18 +1664,6 @@ int ohci_init(void)
if (retval < 0)
continue;
/* TODO check module params here to determine what to load */
#ifdef CONFIG_USB_MOUSE
usb_mouse_init();
#endif
#ifdef CONFIG_USB_KBD
usb_kbd_init();
#endif
hub_init();
#ifdef CONFIG_USB_AUDIO
usb_audio_init();
#endif
#ifdef CONFIG_APM
apm_register_callback(&handle_apm_event);
#endif
......
......@@ -87,9 +87,14 @@ struct ohci_ed {
/* get the head_td */
#define ed_head_td(ed) ((ed)->_head_td & 0xfffffff0)
/* save the carry flag while setting the head_td */
/* save the carry & halted flag while setting the head_td */
#define set_ed_head_td(ed, td) ((ed)->_head_td = (td) | ((ed)->_head_td & 3))
/* Control the ED's halted flag */
#define ohci_halt_ed(ed) ((ed)->_head_td |= 1)
#define ohci_unhalt_ed(ed) ((ed)->_head_td &= ~(__u32)1)
#define ohci_ed_halted(ed) ((ed)->_head_td & 1)
#define OHCI_ED_SKIP (1 << 14)
#define OHCI_ED_MPS (0x7ff << 16)
/* FIXME: should cap at the USB max packet size [0x4ff] */
......@@ -257,12 +262,12 @@ struct ohci_regs {
/*
* Read a MMIO register and re-write it after ANDing with (m)
*/
#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) )
#define writel_mask(m, a) writel( (readl((unsigned long)(a))) & (__u32)(m), (unsigned long)(a) )
/*
* Read a MMIO register and re-write it after ORing with (b)
*/
#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) )
#define writel_set(b, a) writel( (readl((unsigned long)(a))) | (__u32)(b), (unsigned long)(a) )
#define PORT_CCS (1) /* port current connect status */
......@@ -288,6 +293,16 @@ struct ohci_regs {
#define OHCI_ROOT_OCIC (1 << 17) /* Overcurrent indicator change */
#define OHCI_ROOT_CRWE (1 << 31) /* Clear RemoteWakeupEnable */
/*
* Root hub A register masks
*/
#define OHCI_ROOT_A_NPS (1 << 9)
#define OHCI_ROOT_A_PSM (1 << 8)
/*
* Root hub B register masks
*/
/*
* Interrupt register masks
*/
......@@ -334,8 +349,10 @@ struct ohci {
struct list_head interrupt_list; /* List of interrupt active TDs for this OHCI */
};
#define OHCI_TIMER
#define OHCI_TIMER_FREQ (1) /* frequency of OHCI status checks */
#define OHCI_TIMER /* enable the OHCI timer */
#define OHCI_TIMER_FREQ (234) /* ms between each root hub status check */
#undef OHCI_RHSC_INT /* don't use root hub status interrupts */
/* Debugging code */
void show_ohci_ed(struct ohci_ed *ed);
......
......@@ -418,8 +418,8 @@ void *uhci_alloc_isochronous(struct usb_device *usb_dev, unsigned int pipe, void
struct uhci_device *dev = usb_to_uhci(usb_dev);
unsigned long destination, status;
struct uhci_td *td;
int ret, i;
struct uhci_iso_td *isodesc;
int i;
isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL);
if (!isodesc) {
......@@ -700,6 +700,186 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void
return ret;
}
/*
* Bulk thread operations: we just mark the last TD
* in a bulk thread as an interrupt TD, and wake up
* the front-end on completion.
*
* We need to remove the TD from the lists (both interrupt
* list and TD lists) by hand if something bad happens!
*/
static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
static int uhci_bulk_completed(int status, void *buffer, void *dev_id)
{
wake_up(&bulk_wakeup);
return 0; /* Don't re-instate */
}
/* td points to the last td in the list, which interrupts on completion */
static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
{
DECLARE_WAITQUEUE(wait, current);
struct uhci_qh *bulk_qh = uhci_qh_allocate(dev);
struct uhci_td *curtd;
current->state = TASK_UNINTERRUPTIBLE;
add_wait_queue(&bulk_wakeup, &wait);
uhci_add_irq_list(dev->uhci, last, uhci_bulk_completed, NULL);
/* FIXME: This is kinda kludged */
/* Walk the TD list and update the QH pointer */
{
int maxcount = 100;
curtd = first;
do {
curtd->qh = bulk_qh;
if (curtd->link & 1)
break;
curtd = bus_to_virt(curtd->link & ~0xF);
if (!--maxcount) {
printk("runaway tds!\n");
break;
}
} while (1);
}
uhci_insert_tds_in_qh(bulk_qh, first, last);
// bulk0 is empty here...
// show_status(dev->uhci);
// show_queues(dev->uhci);
/* Add it into the skeleton */
/*WARNING! HUB HAS NO BULK QH TIL NOW!!!!!!!!!!!*/
uhci_insert_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh);
// now we're in the queue... but don't ask WHAT is in there ;-(
// show_status(dev->uhci);
// show_queues(dev->uhci);
schedule_timeout(HZ/10);
remove_wait_queue(&bulk_wakeup, &wait);
/* Clean up in case it failed.. */
uhci_remove_irq_list(last);
#if 0
printk("Looking for tds [%p, %p]\n", dev->control_td, td);
#endif
/* Remove it from the skeleton */
uhci_remove_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh);
uhci_qh_deallocate(bulk_qh);
return uhci_td_result(dev, last);
}
/*
* Send or receive a bulk message on a pipe.
*
* Note that the "pipe" structure is set up to map
* easily to the uhci destination fields.
*
* A bulk message is only built up from
* the data phase
*
* The data phase can be an arbitrary number of TD's
* although we currently had better not have more than
* 31 TD's here.
*
* 31 TD's is a minimum of 248 bytes worth of bulk
* information.
*/
static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_td *first, *td, *prevtd;
unsigned long destination, status;
int ret;
if (len > usb_maxpacket(usb_dev->maxpacketsize) * 31)
printk("Warning, too much data for a bulk packet, crashing\n");
/* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */
/*
IS THIS NECCESARY? PERHAPS WE CAN JUST USE THE PIPE
LOOK AT: usb_pipeout and the pipe bits
I FORGOT WHAT IT EXACTLY DOES
*/
if (usb_pipeout(pipe)) {
destination = (pipe & 0x0007ff00) | 0xE1;
}
else {
destination = (pipe & 0x0007ff00) | 0x69;
}
/* Status: slow/fast, Active, Short Packet Detect Three Errors */
status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27);
/*
* Build the TDs for the bulk request
*/
first = td = uhci_td_allocate(dev);
prevtd = first; //This is fake, but at least it's not NULL
while (len > 0) {
/* Build the TD for control status */
int pktsze = len;
int maxsze = usb_maxpacket(pipe);
if (pktsze > maxsze)
pktsze = maxsze;
td->status = status; /* Status */
td->info = destination | ((pktsze-1) << 21); /* pktsze bytes of data */
td->buffer = virt_to_bus(data);
td->backptr = &prevtd->link;
prevtd = td;
td = uhci_td_allocate(dev);
prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */
data += maxsze;
len -= maxsze;
/* Alternate Data0/1 (start with Data0) */
destination ^= 1 << 19;
}
td->link = 1; /* Terminate */
/* Start it up.. */
ret = uhci_run_bulk(dev, first, td);
{
int maxcount = 100;
struct uhci_td *curtd = first;
unsigned int nextlink;
do {
nextlink = curtd->link;
uhci_remove_td(curtd);
uhci_td_deallocate(curtd);
if (nextlink & 1) /* Tail? */
break;
curtd = bus_to_virt(nextlink & ~0xF);
if (!--maxcount) {
printk("runaway td's!?\n");
break;
}
} while (1);
}
return ret;
}
static struct usb_device *uhci_usb_allocate(struct usb_device *parent)
{
struct usb_device *usb_dev;
......@@ -787,6 +967,7 @@ struct usb_operations uhci_device_operations = {
uhci_usb_allocate,
uhci_usb_deallocate,
uhci_control_msg,
uhci_bulk_msg,
uhci_request_irq,
};
......@@ -1399,32 +1580,10 @@ int uhci_init(void)
if (retval < 0)
continue;
#ifdef CONFIG_USB_MOUSE
usb_mouse_init();
#endif
#ifdef CONFIG_USB_KBD
usb_kbd_init();
#endif
hub_init();
#ifdef CONFIG_USB_AUDIO
usb_audio_init();
#endif
#ifdef CONFIG_USB_CPIA
cpia_init();
#endif
#ifdef CONFIG_APM
apm_register_callback(&handle_apm_event);
#endif
return 0;
}
return retval;
}
void cleanup_drivers(void)
{
hub_cleanup();
#ifdef CONFIG_USB_MOUSE
usb_mouse_cleanup();
#endif
}
......@@ -42,6 +42,55 @@
#include "usb.h"
#ifdef CONFIG_USB_UHCI
int uhci_init(void);
#endif
#ifdef CONFIG_USB_OHCI
int ohci_init(void);
#endif
#ifdef CONFIG_USB_OHCI_HCD
int ohci_hcd_init(void);
#endif
int usb_init(void)
{
#ifdef CONFIG_USB_UHCI
uhci_init();
#endif
#ifdef CONFIG_USB_OHCI
ohci_init();
#endif
#ifdef CONFIG_USB_OHCI_HCD
ohci_hcd_init();
#endif
#ifdef CONFIG_USB_MOUSE
usb_mouse_init();
#endif
#ifdef CONFIG_USB_KBD
usb_kbd_init();
#endif
#ifdef CONFIG_USB_AUDIO
usb_audio_init();
#endif
#ifdef CONFIG_USB_ACM
usb_acm_init();
#endif
#ifdef CONFIG_USB_CPIA
usb_cpia_init();
#endif
usb_hub_init();
return 0;
}
void cleanup_drivers(void)
{
hub_cleanup();
#ifdef CONFIG_USB_MOUSE
usb_mouse_cleanup();
#endif
}
/*
* We have a per-interface "registered driver" list.
*/
......@@ -596,20 +645,20 @@ int usb_get_report(struct usb_device *dev)
int usb_get_configuration(struct usb_device *dev)
{
unsigned int cfgno,size;
unsigned int cfgno;
unsigned char buffer[400];
unsigned char * bufptr;
bufptr=buffer;
for (cfgno=0;cfgno<dev->descriptor.bNumConfigurations;cfgno++) {
bufptr = buffer;
for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) {
unsigned int size;
/* Get the first 8 bytes - guaranteed */
if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8))
return -1;
/* Get the full buffer */
size = *(unsigned short *)(bufptr+2);
if (bufptr+size > buffer+sizeof(buffer))
{
if (bufptr+size > buffer+sizeof(buffer)) {
printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size);
size = buffer+sizeof(buffer)-bufptr;
}
......@@ -617,9 +666,9 @@ int usb_get_configuration(struct usb_device *dev)
return -1;
/* Prepare for next configuration */
bufptr+=size;
bufptr += size;
}
return usb_parse_configuration(dev, buffer, size);
return usb_parse_configuration(dev, buffer, bufptr - buffer);
}
/*
......
......@@ -6,6 +6,14 @@
#include <linux/list.h>
#include <linux/sched.h>
extern int usb_hub_init(void);
extern int usb_kbd_init(void);
extern int usb_cpia_init(void);
extern int usb_mouse_init(void);
extern void hub_cleanup(void);
extern void usb_mouse_cleanup(void);
static __inline__ void wait_ms(unsigned int ms)
{
current->state = TASK_UNINTERRUPTIBLE;
......@@ -209,6 +217,7 @@ struct usb_operations {
struct usb_device *(*allocate)(struct usb_device *);
int (*deallocate)(struct usb_device *);
int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int);
int (*bulk_msg)(struct usb_device *, unsigned int, void *, int);
int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
};
......@@ -262,6 +271,7 @@ extern void usb_disconnect(struct usb_device **);
extern void usb_device_descriptor(struct usb_device *dev);
extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len);
extern void usb_destroy_configuration(struct usb_device *dev);
/*
* Calling this entity a "pipe" is glorifying it. A USB pipe
......
......@@ -74,6 +74,7 @@ if [ "$CONFIG_FB" = "y" ]; then
fi
if [ "$ARCH" = "i386" ]; then
bool 'VESA VGA graphics console' CONFIG_FB_VESA
bool 'VGA 16-color graphics console' CONFIG_FB_VGA16
define_bool CONFIG_VIDEO_SELECT y
fi
if [ "$CONFIG_VISWS" = "y" ]; then
......@@ -141,6 +142,7 @@ if [ "$CONFIG_FB" = "y" ]; then
tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
# tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16
tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
bool 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA
else
# Guess what we need
......@@ -283,6 +285,9 @@ if [ "$CONFIG_FB" = "y" ]; then
define_bool CONFIG_FBCON_MAC m
fi
fi
if [ "$CONFIG_FB_VGA16" = "y" ]; then
define_bool CONFIG_FBCON_VGA_PLANES y
fi
if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then
define_bool CONFIG_FBCON_VGA y
else
......
......@@ -202,6 +202,10 @@ ifeq ($(CONFIG_FB_VESA),y)
L_OBJS += vesafb.o
endif
ifeq ($(CONFIG_FB_VGA16),y)
L_OBJS += vga16fb.o
endif
ifeq ($(CONFIG_FB_VIRGE),y)
L_OBJS += virgefb.o
else
......@@ -462,6 +466,14 @@ else
endif
endif
ifeq ($(CONFIG_FBCON_VGA_PLANES),y)
OX_OBJS += fbcon-vga-planes.o
else
ifeq ($(CONFIG_FBCON_VGA_PLANES),m)
MX_OBJS += fbcon-vga-planes.o
endif
endif
ifeq ($(CONFIG_FBCON_VGA),y)
OX_OBJS += fbcon-vga.o
else
......
/*
* linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations
* for VGA 4-plane modes
*
* Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
* Based on code by Michael Schmitz
* Based on the old macfb.c 4bpp code by Alan Cox
*
* 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. */
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/fb.h>
#include <linux/vt_buffer.h>
#include <asm/io.h>
#include <video/fbcon.h>
#include <video/fbcon-vga-planes.h>
#define GRAPHICS_ADDR_REG 0x3ce /* Graphics address register. */
#define GRAPHICS_DATA_REG 0x3cf /* Graphics data register. */
#define SET_RESET_INDEX 0 /* Set/Reset Register index. */
#define ENABLE_SET_RESET_INDEX 1 /* Enable Set/Reset Register index. */
#define DATA_ROTATE_INDEX 3 /* Data Rotate Register index. */
#define GRAPHICS_MODE_INDEX 5 /* Graphics Mode Register index. */
#define BIT_MASK_INDEX 8 /* Bit Mask Register index. */
/* The VGA's weird architecture often requires that we read a byte and
write a byte to the same location. It doesn't matter *what* byte
we write, however. This is because all the action goes on behind
the scenes in the VGA's 32-bit latch register, and reading and writing
video memory just invokes latch behavior.
To avoid race conditions (is this necessary?), reading and writing
the memory byte should be done with a single instruction. One
suitable instruction is the x86 bitwise OR. The following
read-modify-write routine should optimize to one such bitwise
OR. */
static inline void rmw(volatile char *p)
{
*p |= 1;
}
/* Set the Graphics Mode Register. Bits 0-1 are write mode, bit 3 is
read mode. */
static inline void setmode(int mode)
{
outb(GRAPHICS_MODE_INDEX, GRAPHICS_ADDR_REG);
outb(mode, GRAPHICS_DATA_REG);
}
/* Select the Bit Mask Register. */
static inline void selectmask(void)
{
outb(BIT_MASK_INDEX, GRAPHICS_ADDR_REG);
}
/* Set the value of the Bit Mask Register. It must already have been
selected with selectmask(). */
static inline void setmask(int mask)
{
outb(mask, GRAPHICS_DATA_REG);
}
/* Set the Data Rotate Register. Bits 0-2 are rotate count, bits 3-4
are logical operation (0=NOP, 1=AND, 2=OR, 3=XOR). */
static inline void setop(int op)
{
outb(DATA_ROTATE_INDEX, GRAPHICS_ADDR_REG);
outb(op, GRAPHICS_DATA_REG);
}
/* Set the Enable Set/Reset Register. The code here always uses value
0xf for this register. */
static inline void setsr(int sr)
{
outb(ENABLE_SET_RESET_INDEX, GRAPHICS_ADDR_REG);
outb(sr, GRAPHICS_DATA_REG);
}
/* Set the Set/Reset Register. */
static inline void setcolor(int color)
{
outb(SET_RESET_INDEX, GRAPHICS_ADDR_REG);
outb(color, GRAPHICS_DATA_REG);
}
/* Set the value in the Graphics Address Register. */
static inline void setindex(int index)
{
outb(index, GRAPHICS_ADDR_REG);
}
void fbcon_vga_planes_setup(struct display *p)
{
}
void fbcon_vga_planes_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
char *src;
char *dest;
int line_ofs;
int x;
setmode(1);
setop(0);
setsr(0xf);
sy *= fontheight(p);
dy *= fontheight(p);
height *= fontheight(p);
if (dy < sy || (dy == sy && dx < sx)) {
line_ofs = p->line_length - width;
dest = p->screen_base + dx + dy * p->line_length;
src = p->screen_base + sx + sy * p->line_length;
while (height--) {
for (x = 0; x < width; x++)
*dest++ = *src++;
src += line_ofs;
dest += line_ofs;
}
} else {
line_ofs = p->line_length - width;
dest = p->screen_base + dx + width + (dy + height - 1) * p->line_length;
src = p->screen_base + sx + width + (sy + height - 1) * p->line_length;
while (height--) {
for (x = 0; x < width; x++)
*--dest = *--src;
src -= line_ofs;
dest -= line_ofs;
}
}
}
void fbcon_vga_planes_clear(struct vc_data *conp, struct display *p, int sy, int sx,
int height, int width)
{
int line_ofs = p->line_length - width;
char *where;
int x;
setmode(0);
setop(0);
setsr(0xf);
setcolor(attr_bgcol_ec(p, conp));
selectmask();
setmask(0xff);
sy *= fontheight(p);
height *= fontheight(p);
where = p->screen_base + sx + sy * p->line_length;
while (height--) {
for (x = 0; x < width; x++)
*where++ = 0;
where += line_ofs;
}
}
void fbcon_ega_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
{
int fg = attr_fgcol(p,c);
int bg = attr_bgcol(p,c);
int y;
u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
setmode(0);
setop(0);
setsr(0xf);
setcolor(bg);
selectmask();
setmask(0xff);
for (y = 0; y < fontheight(p); y++, where += p->line_length)
rmw(where);
where -= p->line_length * y;
setcolor(fg);
selectmask();
for (y = 0; y < fontheight(p); y++, where += p->line_length)
if (cdat[y]) {
setmask(cdat[y]);
rmw(where);
}
}
void fbcon_vga_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
{
int fg = attr_fgcol(p,c);
int bg = attr_bgcol(p,c);
int y;
u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
setmode(2);
setop(0);
setsr(0xf);
setcolor(fg);
selectmask();
setmask(0xff);
*where = bg;
rmb();
*(volatile char*)where; /* fill latches */
setmode(3);
wmb();
for (y = 0; y < fontheight(p); y++, where += p->line_length)
*where = cdat[y];
wmb();
}
/* 28.50 in my test */
void fbcon_ega_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
int count, int yy, int xx)
{
int fg = attr_fgcol(p,scr_readw(s));
int bg = attr_bgcol(p,scr_readw(s));
char *where;
int n;
setmode(2);
setop(0);
selectmask();
setmask(0xff);
where = p->screen_base + xx + yy * p->line_length * fontheight(p);
*where = bg;
rmb();
*(volatile char*)where;
wmb();
selectmask();
for (n = 0; n < count; n++) {
int c = scr_readw(s++) & p->charmask;
u8 *cdat = p->fontdata + c * fontheight(p);
u8 *end = cdat + fontheight(p);
while (cdat < end) {
outb(*cdat++, GRAPHICS_DATA_REG);
wmb();
*where = fg;
where += p->line_length;
}
where += 1 - p->line_length * fontheight(p);
}
wmb();
}
/* 6.96 in my test */
void fbcon_vga_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
int count, int yy, int xx)
{
int fg = attr_fgcol(p,*s);
int bg = attr_bgcol(p,*s);
char *where;
int n;
setmode(2);
setop(0);
setsr(0xf);
setcolor(fg);
selectmask();
setmask(0xff);
where = p->screen_base + xx + yy * p->line_length * fontheight(p);
*where = bg;
rmb();
*(volatile char*)where; /* fill latches with background */
setmode(3);
wmb();
for (n = 0; n < count; n++) {
int y;
int c = *s++ & p->charmask;
u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
for (y = 0; y < fontheight(p); y++, cdat++) {
*where = *cdat;
where += p->line_length;
}
where += 1 - p->line_length * fontheight(p);
}
wmb();
}
void fbcon_vga_planes_revc(struct display *p, int xx, int yy)
{
char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
int y;
setmode(0);
setop(0x18);
setsr(0xf);
setcolor(0xf);
selectmask();
setmask(0xff);
for (y = 0; y < fontheight(p); y++) {
rmw(where);
where += p->line_length;
}
}
struct display_switch fbcon_vga_planes = {
fbcon_vga_planes_setup, fbcon_vga_planes_bmove, fbcon_vga_planes_clear,
fbcon_vga_planes_putc, fbcon_vga_planes_putcs, fbcon_vga_planes_revc,
NULL, NULL, NULL, FONTWIDTH(8)
};
struct display_switch fbcon_ega_planes = {
fbcon_vga_planes_setup, fbcon_vga_planes_bmove, fbcon_vga_planes_clear,
fbcon_ega_planes_putc, fbcon_ega_planes_putcs, fbcon_vga_planes_revc,
NULL, NULL, NULL, FONTWIDTH(8)
};
#ifdef MODULE
int init_module(void)
{
return 0;
}
void cleanup_module(void)
{}
#endif /* MODULE */
/*
* Visible symbols for modules
*/
EXPORT_SYMBOL(fbcon_vga_planes);
EXPORT_SYMBOL(fbcon_vga_planes_setup);
EXPORT_SYMBOL(fbcon_vga_planes_bmove);
EXPORT_SYMBOL(fbcon_vga_planes_clear);
EXPORT_SYMBOL(fbcon_vga_planes_putc);
EXPORT_SYMBOL(fbcon_vga_planes_putcs);
EXPORT_SYMBOL(fbcon_vga_planes_revc);
EXPORT_SYMBOL(fbcon_ega_planes);
EXPORT_SYMBOL(fbcon_ega_planes_putc);
EXPORT_SYMBOL(fbcon_ega_planes_putcs);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/
......@@ -91,6 +91,9 @@
#include <asm/machdep.h>
#include <asm/setup.h>
#endif
#ifdef CONFIG_FBCON_VGA_PLANES
#include <asm/io.h>
#endif
#define INCLUDE_LINUX_LOGO_DATA
#include <asm/linux_logo.h>
......@@ -2237,6 +2240,35 @@ __initfunc(static int fbcon_show_logo( void ))
done = 1;
}
#endif
#if defined(CONFIG_FBCON_VGA_PLANES)
if (depth == 4 && p->type == FB_TYPE_VGA_PLANES) {
outb_p(1,0x3ce); outb_p(0xf,0x3cf);
outb_p(3,0x3ce); outb_p(0,0x3cf);
outb_p(5,0x3ce); outb_p(0,0x3cf);
src = logo;
for (y1 = 0; y1 < LOGO_H; y1++) {
for (x1 = 0; x1 < LOGO_W / 2; x1++) {
dst = fb + y1*line + x1/4 + x/8;
outb_p(0,0x3ce);
outb_p(*src >> 4,0x3cf);
outb_p(8,0x3ce);
outb_p(1 << (7 - x1 % 4 * 2),0x3cf);
*(volatile char *) dst |= 1;
outb_p(0,0x3ce);
outb_p(*src & 0xf,0x3cf);
outb_p(8,0x3ce);
outb_p(1 << (7 - (1 + x1 % 4 * 2)),0x3cf);
*(volatile char *) dst |= 1;
src++;
}
}
done = 1;
}
#endif
}
if (p->fb_info->fbops->fb_rasterimg)
......@@ -2300,3 +2332,4 @@ struct display_switch fbcon_dummy = {
EXPORT_SYMBOL(fb_display);
EXPORT_SYMBOL(fbcon_redraw_bmove);
EXPORT_SYMBOL(fbcon_dummy);
EXPORT_SYMBOL(fb_con);
......@@ -81,6 +81,8 @@ extern void s3triofb_init(void);
extern void s3triofb_setup(char *options, int *ints);
extern void vesafb_init(void);
extern void vesafb_setup(char *options, int *ints);
extern void vga16fb_init(void);
extern void vga16fb_setup(char *options, int *ints);
extern void matroxfb_init(void);
extern void matroxfb_setup(char* options, int *ints);
extern void hpfb_init(void);
......@@ -164,6 +166,9 @@ static struct {
#ifdef CONFIG_FB_VESA
{ "vesa", vesafb_init, vesafb_setup },
#endif
#ifdef CONFIG_FB_VGA16
{ "vga16", vga16fb_init, vga16fb_setup },
#endif
#ifdef CONFIG_FB_MATROX
{ "matrox", matroxfb_init, matroxfb_setup },
#endif
......
......@@ -597,7 +597,7 @@ __initfunc(void mda_console_init(void))
if (mda_first_vc > mda_last_vc)
return;
take_over_console(&mda_con, mda_first_vc, mda_last_vc, 0);
take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
}
#ifdef MODULE
......
This diff is collapsed.
......@@ -19,6 +19,10 @@ dep_tristate ' MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
dep_tristate ' UMSDOS: Unix-like filesystem on top of standard MSDOS filesystem' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'EFS filesystem support (read only) (experimental)' CONFIG_EFS_FS
fi
tristate 'ISO 9660 CDROM filesystem support' CONFIG_ISO9660_FS
if [ "$CONFIG_ISO9660_FS" != "n" ]; then
bool 'Microsoft Joliet CDROM extensions' CONFIG_JOLIET
......
......@@ -17,8 +17,8 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \
MOD_LIST_NAME := FS_MODULES
ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
hpfs sysv smbfs ncpfs ufs affs romfs autofs hfs lockd nfsd \
nls devpts adfs qnx4
hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
nfsd nls devpts adfs qnx4
ifeq ($(CONFIG_QUOTA),y)
O_OBJS += dquot.o
......@@ -191,6 +191,14 @@ else
endif
endif
ifeq ($(CONFIG_EFS_FS),y)
SUB_DIRS += efs
else
ifeq ($(CONFIG_EFS_FS),m)
MOD_SUB_DIRS += efs
endif
endif
ifeq ($(CONFIG_AFFS_FS),y)
SUB_DIRS += affs
else
......
......@@ -644,7 +644,9 @@ void set_blocksize(kdev_t dev, int size)
clear_bit(BH_Req, &bh->b_state);
bh->b_flushtime = 0;
}
remove_from_hash_queue(bh);
remove_from_queues(bh);
bh->b_dev=B_FREE;
insert_into_queues(bh);
}
}
}
......
.depend
.*.flags
#
# Makefile for the linux efs-filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := efs.o
O_OBJS := super.o inode.o namei.o dir.o file.o symlink.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
/*
* dir.c
*
* Copyright (c) 1999 Al Smith
*/
#include <linux/efs_fs.h>
static int efs_readdir(struct file *, void *, filldir_t);
static struct file_operations efs_dir_operations = {
NULL, /* lseek */
NULL, /* read */
NULL, /* write */
efs_readdir, /* readdir */
NULL, /* poll */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* open */
NULL, /* flush */
NULL, /* release */
NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
NULL /* revalidate */
};
struct inode_operations efs_dir_inode_operations = {
&efs_dir_operations, /* default directory file-ops */
NULL, /* create */
efs_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
efs_bmap, /* bmap */
NULL, /* truncate */
NULL, /* permission */
NULL /* smap */
};
static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
struct inode *inode = filp->f_dentry->d_inode;
struct buffer_head *bh;
struct efs_dir *dirblock;
struct efs_dentry *dirslot;
efs_ino_t inodenum;
efs_block_t block;
int slot, namelen;
char *nameptr;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
if (inode->i_size & (EFS_DIRBSIZE-1))
printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n");
/* work out where this entry can be found */
block = filp->f_pos >> EFS_DIRBSIZE_BITS;
/* each block contains at most 256 slots */
slot = filp->f_pos & 0xff;
/* look at all blocks */
while (block < inode->i_blocks) {
/* read the dir block */
bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_DIRBSIZE);
if (!bh) {
printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block);
break;
}
dirblock = (struct efs_dir *) bh->b_data;
if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
printk(KERN_ERR "EFS: readdir(): invalid directory block\n");
brelse(bh);
break;
}
while (slot < dirblock->slots) {
if (dirblock->space[slot] == 0) {
slot++;
continue;
}
dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
inodenum = be32_to_cpu(dirslot->inode);
namelen = dirslot->namelen;
nameptr = dirslot->name;
#ifdef DEBUG
printk(KERN_DEBUG "EFS: readdir(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", block, slot, dirblock->slots-1, inodenum, nameptr, namelen);
#endif
if (namelen > 0) {
/* found the next entry */
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
/* copy filename and data in dirslot */
filldir(dirent, nameptr, namelen, filp->f_pos, inodenum);
/* sanity check */
if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot);
slot++;
continue;
}
/* store position of next slot */
if (++slot == dirblock->slots) {
slot = 0;
block++;
}
brelse(bh);
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
return 0;
}
slot++;
}
brelse(bh);
slot = 0;
block++;
}
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
return 0;
}
/*
* file.c
*
* Copyright (c) 1999 Al Smith
*
* Portions derived from work (c) 1995,1996 Christian Vogelgsang.
*/
#include <linux/efs_fs.h>
static struct file_operations efs_file_operations = {
NULL, /* lseek */
generic_file_read, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* poll */
NULL, /* ioctl */
generic_file_mmap, /* mmap */
NULL, /* open */
NULL, /* flush */
NULL, /* release */
NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
NULL /* revalidate */
};
struct inode_operations efs_file_inode_operations = {
&efs_file_operations, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
efs_bmap, /* bmap */
NULL, /* truncate */
NULL, /* permission */
NULL /* smap */
};
int efs_bmap(struct inode *inode, efs_block_t block) {
if (block < 0) {
printk(KERN_WARNING "EFS: bmap(): block < 0\n");
return 0;
}
/* are we about to read past the end of a file ? */
if (!(block < inode->i_blocks)) {
#ifdef DEBUG
/*
* i have no idea why this happens as often as it does
*/
printk(KERN_WARNING "EFS: bmap(): block %d >= %ld (filesize %ld)\n",
block,
inode->i_blocks,
inode->i_size);
#endif
return 0;
}
return efs_map_block(inode, block);
}
/*
* inode.c
*
* Copyright (c) 1999 Al Smith
*
* Portions derived from work (c) 1995,1996 Christian Vogelgsang,
* and from work (c) 1998 Mike Shaver.
*/
#include <linux/efs_fs.h>
#include <linux/efs_fs_sb.h>
static inline void extent_copy(efs_extent *src, efs_extent *dst) {
/*
* this is slightly evil. it doesn't just copy
* efs_extent from src to dst, it also mangles
* the bits so that dst ends up in cpu byte-order.
*/
dst->cooked.ex_magic = (unsigned int) src->raw[0];
dst->cooked.ex_bn = ((unsigned int) src->raw[1] << 16) |
((unsigned int) src->raw[2] << 8) |
((unsigned int) src->raw[3] << 0);
dst->cooked.ex_length = (unsigned int) src->raw[4];
dst->cooked.ex_offset = ((unsigned int) src->raw[5] << 16) |
((unsigned int) src->raw[6] << 8) |
((unsigned int) src->raw[7] << 0);
return;
}
void efs_read_inode(struct inode *inode) {
int i, inode_index;
dev_t device;
struct buffer_head *bh;
struct efs_sb_info *sb = SUPER_INFO(inode->i_sb);
struct efs_inode_info *in = INODE_INFO(inode);
efs_block_t block, offset;
struct efs_dinode *efs_inode;
/*
** EFS layout:
**
** | cylinder group | cylinder group | cylinder group ..etc
** |inodes|data |inodes|data |inodes|data ..etc
**
** work out the inode block index, (considering initially that the
** inodes are stored as consecutive blocks). then work out the block
** number of that inode given the above layout, and finally the
** offset of the inode within that block.
*/
inode_index = inode->i_ino /
(EFS_BLOCKSIZE / sizeof(struct efs_dinode));
block = sb->fs_start + sb->first_block +
(sb->group_size * (inode_index / sb->inode_blocks)) +
(inode_index % sb->inode_blocks);
offset = (inode->i_ino %
(EFS_BLOCKSIZE / sizeof(struct efs_dinode))) *
sizeof(struct efs_dinode);
bh = bread(inode->i_dev, block, EFS_BLOCKSIZE);
if (!bh) {
printk(KERN_WARNING "EFS: bread() failed at block %d\n", block);
goto read_inode_error;
}
efs_inode = (struct efs_dinode *) (bh->b_data + offset);
inode->i_mode = be16_to_cpu(efs_inode->di_mode);
inode->i_nlink = be16_to_cpu(efs_inode->di_nlink);
inode->i_uid = be16_to_cpu(efs_inode->di_uid);
inode->i_gid = be16_to_cpu(efs_inode->di_gid);
inode->i_size = be32_to_cpu(efs_inode->di_size);
inode->i_atime = be32_to_cpu(efs_inode->di_atime);
inode->i_mtime = be32_to_cpu(efs_inode->di_mtime);
inode->i_ctime = be32_to_cpu(efs_inode->di_ctime);
/* this is the number of blocks in the file */
if (inode->i_size == 0) {
inode->i_blocks = 0;
} else {
inode->i_blocks = ((inode->i_size - 1) >> EFS_BLOCKSIZE_BITS) + 1;
}
/*
* BUG: irix dev_t is 32-bits. linux dev_t is only 16-bits.
*
* apparently linux will change to 32-bit dev_t sometime during
* linux 2.3.
*
* as is, this code maps devices that can't be represented in
* 16-bits (ie major > 255 or minor > 255) to major = minor = 255.
*
* during 2.3 when 32-bit dev_t become available, we should test
* to see whether odev contains 65535. if this is the case then we
* should then do device = be32_to_cpu(efs_inode->di_u.di_dev.ndev).
*/
device = be16_to_cpu(efs_inode->di_u.di_dev.odev);
/* get the number of extents for this object */
in->numextents = be16_to_cpu(efs_inode->di_numextents);
in->lastextent = 0;
/* copy the extents contained within the inode to memory */
for(i = 0; i < EFS_DIRECTEXTENTS; i++) {
extent_copy(&(efs_inode->di_u.di_extents[i]), &(in->extents[i]));
if (i < in->numextents && in->extents[i].cooked.ex_magic != 0) {
printk(KERN_WARNING "EFS: extent %d has bad magic number in inode %lu\n", i, inode->i_ino);
brelse(bh);
goto read_inode_error;
}
}
brelse(bh);
#ifdef DEBUG
printk(KERN_DEBUG "EFS: read_inode(): inode %lu, extents %d, mode %o\n",
inode->i_ino, in->numextents, inode->i_mode);
#endif
switch (inode->i_mode & S_IFMT) {
case S_IFDIR:
inode->i_op = &efs_dir_inode_operations;
break;
case S_IFREG:
inode->i_op = &efs_file_inode_operations;
break;
case S_IFLNK:
inode->i_op = &efs_symlink_inode_operations;
break;
case S_IFCHR:
inode->i_rdev = device;
inode->i_op = &chrdev_inode_operations;
break;
case S_IFBLK:
inode->i_rdev = device;
inode->i_op = &blkdev_inode_operations;
break;
case S_IFIFO:
init_fifo(inode);
break;
default:
printk(KERN_WARNING "EFS: unsupported inode mode %o\n", inode->i_mode);
goto read_inode_error;
break;
}
return;
read_inode_error:
printk(KERN_WARNING "EFS: failed to read inode %lu\n", inode->i_ino);
inode->i_mode = S_IFREG;
inode->i_atime = 0;
inode->i_ctime = 0;
inode->i_mtime = 0;
inode->i_nlink = 1;
inode->i_size = 0;
inode->i_blocks = 0;
inode->i_uid = 0;
inode->i_gid = 0;
inode->i_op = NULL;
return;
}
static inline efs_block_t
efs_extent_check(efs_extent *ptr, efs_block_t block, struct efs_sb_info *sb) {
efs_block_t start;
efs_block_t length;
efs_block_t offset;
/*
* given an extent and a logical block within a file,
* can this block be found within this extent ?
*/
start = ptr->cooked.ex_bn;
length = ptr->cooked.ex_length;
offset = ptr->cooked.ex_offset;
if ((block >= offset) && (block < offset+length)) {
return(sb->fs_start + start + block - offset);
} else {
return 0;
}
}
efs_block_t efs_map_block(struct inode *inode, efs_block_t block) {
struct efs_sb_info *sb = SUPER_INFO(inode->i_sb);
struct efs_inode_info *in = INODE_INFO(inode);
struct buffer_head *bh = NULL;
int cur, last, first = 1;
int ibase, ioffset, dirext, direxts, indext, indexts;
efs_block_t iblock, result = 0, lastblock = 0;
efs_extent ext, *exts;
last = in->lastextent;
if (in->numextents <= EFS_DIRECTEXTENTS) {
/* first check the last extent we returned */
if ((result = efs_extent_check(&in->extents[last], block, sb)))
return result;
/* if we only have one extent then nothing can be found */
if (in->numextents == 1) {
printk(KERN_ERR "EFS: map_block() failed to map (1 extent)\n");
return 0;
}
direxts = in->numextents;
/*
* check the stored extents in the inode
* start with next extent and check forwards
*/
for(dirext = 1; dirext < direxts; dirext++) {
cur = (last + dirext) % in->numextents;
if ((result = efs_extent_check(&in->extents[cur], block, sb))) {
in->lastextent = cur;
return result;
}
}
printk(KERN_ERR "EFS: map_block() failed to map block %u (dir)\n", block);
return 0;
}
#ifdef DEBUG
printk(KERN_DEBUG "EFS: map_block(): indirect search for logical block %u\n", block);
#endif
direxts = in->extents[0].cooked.ex_offset;
indexts = in->numextents;
for(indext = 0; indext < indexts; indext++) {
cur = (last + indext) % indexts;
/*
* work out which direct extent contains `cur'.
*
* also compute ibase: i.e. the number of the first
* indirect extent contained within direct extent `cur'.
*
*/
ibase = 0;
for(dirext = 0; cur < ibase && dirext < direxts; dirext++) {
ibase += in->extents[dirext].cooked.ex_length *
(EFS_BLOCKSIZE / sizeof(efs_extent));
}
if (dirext == direxts) {
/* should never happen */
printk(KERN_ERR "EFS: couldn't find direct extent for indirect extent %d (block %u)\n", cur, block);
if (bh) brelse(bh);
return 0;
}
/* work out block number and offset of this indirect extent */
iblock = sb->fs_start + in->extents[dirext].cooked.ex_bn +
(cur - ibase) /
(EFS_BLOCKSIZE / sizeof(efs_extent));
ioffset = (cur - ibase) %
(EFS_BLOCKSIZE / sizeof(efs_extent));
if (first || lastblock != iblock) {
if (bh) brelse(bh);
bh = bread(inode->i_dev, iblock, EFS_BLOCKSIZE);
if (!bh) {
printk(KERN_ERR "EFS: bread() failed at block %d\n", iblock);
return 0;
}
#ifdef DEBUG
printk(KERN_DEBUG "EFS: map_block(): read indirect extent block %d\n", iblock);
#endif
first = 0;
lastblock = iblock;
}
exts = (efs_extent *) bh->b_data;
extent_copy(&(exts[ioffset]), &ext);
if (ext.cooked.ex_magic != 0) {
printk(KERN_ERR "EFS: extent %d has bad magic number in block %d\n", cur, iblock);
if (bh) brelse(bh);
return 0;
}
if ((result = efs_extent_check(&ext, block, sb))) {
if (bh) brelse(bh);
in->lastextent = cur;
return result;
}
}
if (bh) brelse(bh);
printk(KERN_ERR "EFS: map_block() failed to map block %u (indir)\n", block);
return 0;
}
/*
* namei.c
*
* Copyright (c) 1999 Al Smith
*
* Portions derived from work (c) 1995,1996 Christian Vogelgsang.
*/
#include <linux/efs_fs.h>
static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) {
struct buffer_head *bh;
int slot, namelen;
char *nameptr;
struct efs_dir *dirblock;
struct efs_dentry *dirslot;
efs_ino_t inodenum;
efs_block_t block;
if (inode->i_size & (EFS_DIRBSIZE-1))
printk(KERN_WARNING "EFS: WARNING: find_entry(): directory size not a multiple of EFS_DIRBSIZE\n");
for(block = 0; block < inode->i_blocks; block++) {
bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_DIRBSIZE);
if (!bh) {
printk(KERN_ERR "EFS: find_entry(): failed to read dir block %d\n", block);
return 0;
}
dirblock = (struct efs_dir *) bh->b_data;
if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
printk(KERN_ERR "EFS: find_entry(): invalid directory block\n");
brelse(bh);
return(0);
}
for(slot = 0; slot < dirblock->slots; slot++) {
dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
namelen = dirslot->namelen;
nameptr = dirslot->name;
if ((namelen == len) && (!memcmp(name, nameptr, len))) {
inodenum = be32_to_cpu(dirslot->inode);
brelse(bh);
return(inodenum);
}
}
brelse(bh);
}
return(0);
}
struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry) {
efs_ino_t inodenum;
struct inode * inode;
if (!dir || !S_ISDIR(dir->i_mode))
return ERR_PTR(-ENOENT);
inode = NULL;
inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
if (inodenum) {
if (!(inode = iget(dir->i_sb, inodenum)))
return ERR_PTR(-EACCES);
}
d_add(dentry, inode);
return NULL;
}
This diff is collapsed.
/*
* symlink.c
*
* Copyright (c) 1999 Al Smith
*
* Portions derived from work (c) 1995,1996 Christian Vogelgsang.
*/
#include <linux/malloc.h>
#include <linux/efs_fs.h>
static int efs_readlink(struct dentry *, char *, int);
static struct dentry * efs_follow_link(struct dentry *, struct dentry *, unsigned int);
struct inode_operations efs_symlink_inode_operations = {
NULL, /* no symlink file-operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
efs_readlink, /* readlink */
efs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL, /* permission */
NULL /* smap */
};
static char *efs_linktarget(struct inode *in, int *len) {
char *name;
struct buffer_head * bh;
efs_block_t size = in->i_size;
if (size > 2 * EFS_BLOCKSIZE) {
printk(KERN_ERR "EFS: linktarget(): name too long: %lu\n", in->i_size);
return NULL;
}
if (!(name = kmalloc(size + 1, GFP_KERNEL)))
return NULL;
/* read first 512 bytes of link target */
bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCKSIZE);
if (!bh) {
kfree(name);
printk(KERN_ERR "EFS: linktarget(): couldn't read block %d\n", efs_bmap(in, 0));
return NULL;
}
memcpy(name, bh->b_data, (size > EFS_BLOCKSIZE) ? EFS_BLOCKSIZE : size);
brelse(bh);
if (size > EFS_BLOCKSIZE) {
bh = bread(in->i_dev, efs_bmap(in, 1), EFS_BLOCKSIZE);
if (!bh) {
kfree(name);
printk(KERN_ERR "EFS: linktarget(): couldn't read block %d\n", efs_bmap(in, 1));
return NULL;
}
memcpy(name + EFS_BLOCKSIZE, bh->b_data, size - EFS_BLOCKSIZE);
brelse(bh);
}
name[size] = (char) 0;
if (len) *len = size;
return name;
}
static struct dentry *efs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow) {
char *name;
struct inode *inode = dentry->d_inode;
if (!(name = efs_linktarget(inode, NULL))) {
dput(base);
return ERR_PTR(-ELOOP);
}
base = lookup_dentry(name, base, follow);
kfree(name);
return base;
}
static int efs_readlink(struct dentry * dir, char * buf, int bufsiz) {
int rc;
char *name;
struct inode *inode = dir->d_inode;
if (!(name = efs_linktarget(inode, &bufsiz))) return 0;
rc = copy_to_user(buf, name, bufsiz) ? -EFAULT : bufsiz;
kfree(name);
return rc;
}
......@@ -407,8 +407,9 @@ void ext2_truncate (struct inode * inode)
break;
if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
ext2_sync_inode (inode);
current->counter = 0;
schedule ();
run_task_queue(&tq_disk);
current->policy |= SCHED_YIELD;
schedule();
}
/*
* If the file is not being truncated to a block boundary, the
......
This diff is collapsed.
This diff is collapsed.
......@@ -18,9 +18,11 @@
extern struct file_operations fat_dir_operations;
EXPORT_SYMBOL(fat_add_cluster);
EXPORT_SYMBOL(fat_add_cluster1);
EXPORT_SYMBOL(fat_bmap);
EXPORT_SYMBOL(fat_brelse);
EXPORT_SYMBOL(fat_cache_inval_inode);
EXPORT_SYMBOL(fat_clear_inode);
EXPORT_SYMBOL(fat_date_unix2dos);
EXPORT_SYMBOL(fat_delete_inode);
EXPORT_SYMBOL(fat_dir_operations);
......@@ -28,17 +30,18 @@ EXPORT_SYMBOL(fat_esc2uni);
EXPORT_SYMBOL(fat_file_read);
EXPORT_SYMBOL(fat_file_write);
EXPORT_SYMBOL(fat_fs_panic);
EXPORT_SYMBOL(fat_get_entry);
EXPORT_SYMBOL(fat__get_entry);
EXPORT_SYMBOL(fat_lock_creation);
EXPORT_SYMBOL(fat_mark_buffer_dirty);
EXPORT_SYMBOL(fat_mmap);
EXPORT_SYMBOL(fat_notify_change);
EXPORT_SYMBOL(fat_parent_ino);
EXPORT_SYMBOL(fat_put_inode);
EXPORT_SYMBOL(fat_put_super);
EXPORT_SYMBOL(fat_read_inode);
EXPORT_SYMBOL(fat_attach);
EXPORT_SYMBOL(fat_detach);
EXPORT_SYMBOL(fat_build_inode);
EXPORT_SYMBOL(fat_read_super);
EXPORT_SYMBOL(fat_readdirx);
EXPORT_SYMBOL(fat_search_long);
EXPORT_SYMBOL(fat_readdir);
EXPORT_SYMBOL(fat_scan);
EXPORT_SYMBOL(fat_smap);
......@@ -54,9 +57,11 @@ EXPORT_SYMBOL(lock_fat);
EXPORT_SYMBOL(unlock_fat);
EXPORT_SYMBOL(fat_dir_ioctl);
EXPORT_SYMBOL(fat_readpage);
EXPORT_SYMBOL(fat_is_binary);
EXPORT_SYMBOL(fat_add_entries);
EXPORT_SYMBOL(fat_dir_empty);
int init_fat_fs(void)
{
fat_hash_init();
return 0;
}
This diff is collapsed.
This diff is collapsed.
......@@ -22,6 +22,7 @@
#include <linux/ncp_fs.h>
#include <linux/affs_fs.h>
#include <linux/ufs_fs.h>
#include <linux/efs_fs.h>
#include <linux/romfs_fs.h>
#include <linux/auto_fs.h>
#include <linux/qnx4_fs.h>
......@@ -129,6 +130,10 @@ void __init filesystem_setup(void)
init_ufs_fs();
#endif
#ifdef CONFIG_EFS_FS
init_efs_fs();
#endif
#ifdef CONFIG_AUTOFS_FS
init_autofs_fs();
#endif
......
#
# Makefile for the Linux HPFS filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := hpfs.o
O_OBJS := hpfs_fs.o hpfs_caps.o
M_OBJS := $(O_TARGET)
O_OBJS := alloc.o anode.o buffer.o dentry.o dir.o dnode.o ea.o file.o inode.o map.o mmap.o name.o namei.o super.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
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.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
unsigned hpfs_char_to_linux (unsigned c);
unsigned hpfs_char_to_lower_linux (unsigned c);
unsigned hpfs_char_to_upper_linux (unsigned c);
unsigned linux_char_to_upper_linux (unsigned c);
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.
This diff is collapsed.
This diff is collapsed.
......@@ -20,11 +20,9 @@
EXPORT_SYMBOL(msdos_create);
EXPORT_SYMBOL(msdos_lookup);
EXPORT_SYMBOL(msdos_mkdir);
EXPORT_SYMBOL(msdos_read_inode);
EXPORT_SYMBOL(msdos_rename);
EXPORT_SYMBOL(msdos_rmdir);
EXPORT_SYMBOL(msdos_unlink);
EXPORT_SYMBOL(msdos_unlink_umsdos);
EXPORT_SYMBOL(msdos_read_super);
EXPORT_SYMBOL(msdos_put_super);
......
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.
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.
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.
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.
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.
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.
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