S: Victoria Park 6100
S: Australia
+N: Martin Mares
+E: mj@k332.feld.cvut.cz
+D: BIOS video mode handling code
+D: Miscellaneous kernel fixes
+D: MOXA C-218 serial board driver
+S: Kankovskeho 1241
+S: 182 00 Praha 8
+S: Czech Republic
+
N: John A. Martin
E: jam@acm.org
D: FSSTND contributor
{\end{tabbing}}
%
\title{{\bf Linux Allocated Devices}}
-\author{Maintained by H. Peter Anvin $<$Peter.Anvin@linux.org$>$}
-\date{Last revised: September 20, 1995}
+\author{Maintained by H. Peter Anvin $<$hpa@storm.net$>$}
+\date{Last revised: November 17, 1995}
\maketitle
%
\noindent
\major{ }{}{block}{Fourth IDE hard disk/CD-ROM interface}
\major{35}{}{char }{tclmidi MIDI driver}
\major{ }{}{block}{Modular RAM disk}
-\major{36}{}{block}{MCA ESDI hard disk}
-\major{37--223}{}{}{Unallocated}
-\major{224--254}{}{}{Local use}
+\major{36}{}{char }{Netlink support}
+\major{ }{}{block}{MCA ESDI hard disk}
+\major{37}{--41}{}{Unallocated}
+\major{42}{}{}{Demo/sample use}
+\major{43}{--223}{}{Unallocated}
+\major{224}{--239}{}{SEE NOTE}
+\major{240}{--254}{}{Local use}
\major{255}{}{}{Reserved}
\end{devicelist}
\end{devicelist}
\begin{devicelist}
-\major{36}{}{block}{MCA ESDI hard disk}
+\major{36}{}{char }{Netlink support}
+ \minor{0}{/dev/route}{Routing, device updates (kernel to user)}
+ \minor{1}{/dev/skip}{enSKIP security cache control}
+\\
+\major{ }{}{block}{MCA ESDI hard disk}
\minor{0}{/dev/eda}{First ESDI disk whole disk}
\minor{64}{/dev/edb}{Second ESDI disk whole disk}
\minordots
3).
\begin{devicelist}
-\major{37}{--223}{}{Unallocated}
+\major{37}{--41}{}{Unallocated}
+\end{devicelist}
+
+\begin{devicelist}
+\major{42}{}{}{Demo/sample use}
+\end{devicelist}
+
+\noindent
+This number is indended for use in sample code, as well as a general
+``example'' device number. It should never be used for a device
+driver that is being distributed; either obtain an official number or
+use the local/experimental range. The sudden addition or removal of a
+driver with this number should not cause ill effects to the system
+(bugs excepted.)
+
+\begin{devicelist}
+\major{43}{--223}{}{Unallocated}
\end{devicelist}
\begin{devicelist}
-\major{224}{--254}{}{Local/experimental use}
+\major{224}{--239}{}{SEE NOTE}
+\end{devicelist}
+
+\noindent
+This range is currently assigned as part of the local/experimental
+range. However, because of the Linux way of setting a limit on the
+highest device number in the system, currently set at 63 by default, I
+am considering changing the local/experimental use to 60--63,
+120--127, 240--254. If you are currently using the range 224--239 and
+such a change would pose a problem for you, please contact
+$<$hpa@storm.net$>$ as soon as possible.
+
+\begin{devicelist}
+\major{240}{--254}{}{Local/experimental use}
\end{devicelist}
\noindent
\vlink{/dev/mouse}{mouse port}{symbolic}{Current mouse device}
\vlink{/dev/tape}{tape device}{symbolic}{Current tape device}
\vlink{/dev/cdrom}{CD-ROM device}{symbolic}{Current CD-ROM device}
+\vlink{/dev/cdwriter}{CD-writer}{symbolic}{Current CD-writer device}
+\vlink{/dev/scanner}{scanner device}{symbolic}{Current scanner device}
\vlink{/dev/modem}{modem port}{symbolic}{Current dialout device}
\vlink{/dev/root}{root device}{symbolic}{Current root filesystem}
\vlink{/dev/swap}{swap device}{symbolic}{Current swap device}
If it exists, {\file /dev/modem} should point to the appropriate
dialout (alternate) device.
+For SCSI devices, {\file /dev/tape} and {\file /dev/cdrom} should
+point to the ``cooked'' devices ({\file /dev/st*} and {\file
+/dev/sr*}, respectively), whereas {\file /dev/cdwriter} and {\file
+/dev/scanner} should point to the appropriate generic SCSI devices
+({\file /dev/sg*}.)
+
+{\file /dev/mouse} may point to a dialout (alternate) TTY device, a
+hardware mouse device, or a socket for a mouse driver program.
+
\subsection{Sockets and pipes}
Non-transient sockets or named pipes may exist in {\file /dev}.
\end{nodelist}
\end{document}
+
...
255 = /dev/ram255 256th modular RAM disk
- 36 block MCA ESDI hard disk
+ 36 char Netlink support
+ 0 = /dev/route Routing, device updates, kernel to user
+ 1 = /dev/skip enSKIP security cache control
+ block MCA ESDI hard disk
0 = /dev/eda First ESDI disk whole disk
64 = /dev/edb Second ESDI disk whole disk
...
Partitions are handled in the same way as IDE disks
(see major number 3).
- 37-223 UNALLOCATED
+ 37-41 UNALLOCATED
-224-254 LOCAL USE
+ 42 Demo/sample use
+
+ This number is indended for use in sample code, as
+ well as a general "example" device number. It
+ should never be used for a device driver that is being
+ distributed; either obtain an official number or use
+ the local/experimental range. The sudden addition or
+ removal of a driver with this number should not cause
+ ill effects to the system (bugs excepted.)
+
+ 43-223 UNALLOCATED
+
+224-239 SEE NOTE
+
+ This range is currently assigned as part of the
+ local/experimental range. However, because of the
+ Linux way of setting a limit on the highest device
+ number in the system, currently set at 63 by default,
+ I am considering changing the local/experimental use
+ to 60-63, 120-127, 240-254. If you are currently
+ using the range 224-239 and such a change would pose a
+ problem for you, please contact <hpa@storm.net> as
+ soon as possible.
+
+240-254 LOCAL USE
Allocated for local/experimental use
Please note that MAX_CHRDEV and MAX_BLKDEV in
/dev/mouse mouse port symbolic Current mouse device
/dev/tape tape device symbolic Current tape device
/dev/cdrom CD-ROM device symbolic Current CD-ROM device
+/dev/cdwriter CD-writer symbolic Current CD-writer device
+/dev/scanner scanner symbolic Current scanner device
/dev/modem modem port symbolic Current dialout device
/dev/root root device symbolic Current root filesystem
/dev/swap swap device symbolic Current swap device
exists, /dev/modem shold point to the appropriate dialout (alternate)
device.
+For SCSI devices, /dev/tape and /dev/cdrom should point to the
+``cooked'' devices (/dev/st* and /dev/sr*, respectively), whereas
+/dev/cdwriter and /dev/scanner should point to the appropriate generic
+SCSI devices (/dev/sg*).
+
+/dev/mouse may point to a dialout (alternate) TTY device, a hardware
+mouse device, or a socket for a mouse driver program.
Sockets and pipes
user-defined map now defaults to U+F000 to U+F1FF, emulating the
previous behaviour.
+Actual characters assigned in the Corporate Zone
+------------------------------------------------
+
In addition, the following characters not present in Unicode 1.1.4 (at
least, I have not found them!) have been defined; these are used by
the DEC VT graphics map:
character, and hence has been coded as U+2500 FORMS LIGHT HORIZONTAL.
However, I left U+F802 blank should the need arise.
- H. Peter Anvin <Peter.Anvin@linux.org>
- Yggdrasil Computing, Inc.
+Klingon language support
+------------------------
+
+Unfortunately, Unicode/ISO 10646 does not allocate code points for the
+language Klingon, probably fearing the potential code point explosion
+if many fictional lanugages were submitted for inclusion. There are
+also political reasons (the Japanese, for example, are not too happy
+about the whole 16-bit concept to begin with.) However, with Linux
+being a hacker-driven OS it seems this is a brilliant linguistic hack
+worth supporting. Hence I have chosen to add it to the list in the
+Linux "Corporate" Zone.
+
+Several glyph forms for the Klingon alphabet has been proposed.
+However, since the set of symbols appear to be consistent throughout,
+with only the actual shapes being different, in keeping with standard
+Unicode practice these differences are considered font variants.
+
+Klingon has an alphabet of 26 characters, a positional numeric writing
+system with 10 digits, and is written left-to-right, top-to-bottom.
+Punctuation appears to be only used in Latin transliteration; it is
+appears customary to write each sentence on its own line, and
+centered. Space has been reserved for punctuation should it prove
+necessary.
+
+This encoding has been endorsed by the Klingon Language Institute.
+For more information, contact them at:
+
+ http://www.kli.org/
+
+Since the characters in the beginning of the Linux CZ have been more
+of the dingbats/symbols/forms type and this is a language, I have
+located it at the end, on a 16-cell boundary in keeping with standard
+Unicode practice.
+
+U+F8D0 KLINGON LETTER A
+U+F8D1 KLINGON LETTER B
+U+F8D2 KLINGON LETTER CH
+U+F8D3 KLINGON LETTER D
+U+F8D4 KLINGON LETTER E
+U+F8D5 KLINGON LETTER GH
+U+F8D6 KLINGON LETTER H
+U+F8D7 KLINGON LETTER I
+U+F8D8 KLINGON LETTER J
+U+F8D9 KLINGON LETTER L
+U+F8DA KLINGON LETTER M
+U+F8DB KLINGON LETTER N
+U+F8DC KLINGON LETTER NG
+U+F8DD KLINGON LETTER O
+U+F8DE KLINGON LETTER P
+U+F8DF KLINGON LETTER Q
+ - Written <q> in standard Okrand Latin transliteration
+U+F8E0 KLINGON LETTER QH
+ - Written <Q> in standard Okrand Latin transliteration
+U+F8E1 KLINGON LETTER R
+U+F8E2 KLINGON LETTER S
+U+F8E3 KLINGON LETTER T
+U+F8E4 KLINGON LETTER TLH
+U+F8E5 KLINGON LETTER U
+U+F8E6 KLINGON LETTER V
+U+F8E7 KLINGON LETTER W
+U+F8E8 KLINGON LETTER Y
+U+F8E9 KLINGON LETTER GLOTTAL STOP
+
+U+F8F0 KLINGON DIGIT ZERO
+U+F8F1 KLINGON DIGIT ONE
+U+F8F2 KLINGON DIGIT TWO
+U+F8F3 KLINGON DIGIT THREE
+U+F8F4 KLINGON DIGIT FOUR
+U+F8F5 KLINGON DIGIT FIVE
+U+F8F6 KLINGON DIGIT SIX
+U+F8F7 KLINGON DIGIT SEVEN
+U+F8F8 KLINGON DIGIT EIGHT
+U+F8F9 KLINGON DIGIT NINE
+
+
+ H. Peter Anvin <hpa@storm.net>
VERSION = 1
PATCHLEVEL = 3
-SUBLEVEL = 42
+SUBLEVEL = 43
ARCH = i386
void show_regs(struct pt_regs * regs)
{
- printk("\nps: %04lx pc: %016lx\n", regs->ps, regs->pc);
- printk("rp: %016lx sp: %p\n", regs->r26, regs+1);
+ printk("\nps: %04lx pc: [<%016lx>]\n", regs->ps, regs->pc);
+ printk("rp: [<%016lx>] sp: %p\n", regs->r26, regs+1);
printk(" r0: %016lx r1: %016lx r2: %016lx r3: %016lx\n",
regs->r0, regs->r1, regs->r2, regs->r3);
printk(" r4: %016lx r5: %016lx r6: %016lx r7: %016lx\n",
return;
printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
sp = (unsigned long) (regs+1);
- printk("pc = %lx ps = %04lx\n", regs->pc, regs->ps);
- printk("rp = %lx sp = %lx\n", regs->r26, sp);
+ printk("pc = [<%lx>] ps = %04lx\n", regs->pc, regs->ps);
+ printk("rp = [<%lx>] sp = %lx\n", regs->r26, sp);
printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
regs->r0, regs->r1, regs->r2, regs->r3);
printk("r8=%lx\n", regs->r8);
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
- if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
+ if (expand_stack(vma, address))
goto bad_area;
- vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
- vma->vm_start = (address & PAGE_MASK);
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
* adapted for Linux.
*
* malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
- * puts by Nick Holloway 1993
+ * puts by Nick Holloway 1993, better puts by Martin Mares 1995
*/
#include "gzip.h"
#include "lzw.h"
#include <asm/segment.h>
+#include <asm/io.h>
/*
* These are set up by the setup-routine at boot-time:
unsigned short orig_video_page;
unsigned char orig_video_mode;
unsigned char orig_video_cols;
- unsigned short orig_video_ega_ax;
+ unsigned short unused2;
unsigned short orig_video_ega_bx;
- unsigned short orig_video_ega_cx;
+ unsigned short unused3;
unsigned char orig_video_lines;
unsigned char orig_video_isVGA;
};
local int get_method(int);
char *vidmem = (char *)0xb8000;
+int vidport;
int lines, cols;
static void puts(const char *);
static void puts(const char *s)
{
- int x,y;
+ int x,y,pos;
char c;
x = SCREEN_INFO.orig_x;
SCREEN_INFO.orig_x = x;
SCREEN_INFO.orig_y = y;
+
+ pos = (x + cols * y) * 2; /* Update cursor position */
+ outb_p(14, vidport);
+ outb_p(0xff & (pos >> 9), vidport+1);
+ outb_p(15, vidport);
+ outb_p(0xff & (pos >> 1), vidport+1);
}
__ptr_t memset(__ptr_t s, int c, size_t n)
void decompress_kernel()
{
- if (SCREEN_INFO.orig_video_mode == 7)
+ if (SCREEN_INFO.orig_video_mode == 7) {
vidmem = (char *) 0xb0000;
- else
+ vidport = 0x3b4;
+ } else {
vidmem = (char *) 0xb8000;
+ vidport = 0x3d4;
+ }
lines = SCREEN_INFO.orig_video_lines;
cols = SCREEN_INFO.orig_video_cols;
#endif
cmpl SYMBOL_NAME(task),%eax # task[0] cannot have signals
je 2f
- cmpl $0,state(%eax) # state
- jne reschedule
- cmpl $0,counter(%eax) # counter
- je reschedule
movl blocked(%eax),%ecx
movl %ecx,%ebx # save blocked in %ebx for signal handling
notl %ecx
.long SYMBOL_NAME(sys_msync)
.long SYMBOL_NAME(sys_readv) /* 145 */
.long SYMBOL_NAME(sys_writev)
- .space (NR_syscalls-146)*4
+ .long 0
+ .long 0
+ .long 0
+ .long SYMBOL_NAME(sys_mlock) /* 150 */
+ .long SYMBOL_NAME(sys_munlock)
+ .long SYMBOL_NAME(sys_mlockall)
+ .long SYMBOL_NAME(sys_munlockall)
+ .space (NR_syscalls-154)*4
void show_regs(struct pt_regs * regs)
{
printk("\n");
- printk("EIP: %04x:%08lx",0xffff & regs->cs,regs->eip);
+ printk("EIP: %04x:[<%08lx>]",0xffff & regs->cs,regs->eip);
if (regs->cs & 3)
printk(" ESP: %04x:%08lx",0xffff & regs->ss,regs->esp);
printk(" EFLAGS: %08lx\n",regs->eflags);
*/
/*
- * This file handles the architecture-dependent parts of process handling..
+ * This file handles the architecture-dependent parts of initialization
*/
#include <linux/errno.h>
request_region(0xf0,0x10,"npu");
}
+static const char * i486model(unsigned int nr)
+{
+ static const char *model[] = {
+ "0", "DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4"
+ };
+ if (nr < sizeof(model)/sizeof(char *))
+ return model[nr];
+ return "Unknown";
+}
+
+static const char * i586model(unsigned int nr)
+{
+ static const char *model[] = {
+ "0", "Pentium 60/66","Pentium 75+"
+ };
+ if (nr < sizeof(model)/sizeof(char *))
+ return model[nr];
+ return "Unknown";
+}
+
+static const char * getmodel(int x86, int model)
+{
+ switch (x86) {
+ case 4:
+ return i486model(model);
+ case 5:
+ return i586model(model);
+ }
+ return "Unknown";
+}
+
int get_cpuinfo(char * buffer)
{
- static const char *model[2][9]={{"DX","SX","DX/2","4","SX/2","6",
- "DX/2-WB","DX/4"},
- {"Pentium 60/66","Pentium 75+","3",
- "4","5","6","7","8"}};
char mask[2];
#ifndef __SMP__
mask[0] = x86_mask+'@';
"CMPXCHGB8B\t: %s\n"
"BogoMips\t: %lu.%02lu\n",
x86+'0',
- x86_model ? model[x86-4][x86_model-1] : "Unknown",
+ getmodel(x86, x86_model),
x86_mask ? mask : "Unknown",
x86_vendor_id,
fdiv_bug ? "yes" : "no",
bp+=sprintf(bp,"\nmodel\t\t: ");
for(i=0;i<32;i++)
if(cpu_present_map&(1<<i))
- bp+=sprintf(bp,"%-16s",cpu_data[i].x86_model?
- model[cpu_data[i].x86-4][cpu_data[i].x86_model-1]:"Unknown");
+ bp+=sprintf(bp,"%-16s",getmodel(cpu_data[i].x86,cpu_data[i].x86_model));
bp+=sprintf(bp,"\nmask\t\t: ");
for(i=0;i<32;i++)
if(cpu_present_map&(1<<i))
asmlinkage int system_call(void);
asmlinkage void lcall7(void);
-struct desc_struct default_ldt;
+struct desc_struct default_ldt = { 0, 0 };
static inline void console_verbose(void)
{
console_verbose();
printk("%s: %04lx\n", str, err & 0xffff);
printk("CPU: %d\n", smp_processor_id());
- printk("EIP: %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags);
+ printk("EIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags);
printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
regs->eax, regs->ebx, regs->ecx, regs->edx);
printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
((addr >= module_start) && (addr <= module_end))) {
if (i && ((i % 8) == 0))
printk("\n ");
- printk("%08lx ", addr);
+ printk("[<%08lx>] ", addr);
i++;
}
}
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
- if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
- goto bad_area;
if (error_code & 4) {
/*
* accessing the stack below %esp is always a bug.
if (address + 32 < regs->esp)
goto bad_area;
}
- vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
- vma->vm_start = (address & PAGE_MASK);
+ if (expand_stack(vma, address))
+ goto bad_area;
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
- PCI support is automatic
- for VLB, use kernel command line option: ide0=cmd640_vlb
- this support also enables the secondary i/f on most cards
+ - experimental interface timing parameter support
+NEW! - experimental support for UMC 8672 interfaces
NEW! - support for secondary interface on the FGI/Holtek HT-6560B VLB i/f
- use kernel command line option: ide1=ht6560
NEW! - experimental "fast" speed support for QD6580 interfaces
NEW! - transparent support for DiskManager 6.0x and "Dynamic Disk Overlay"
- works with Linux fdisk, LILO, loadlin, bootln, etc..
NEW! - mostly transparent support for EZ-Drive
- - LILO is incompatible (also harmless) with EZ-Drive
+NEW! - to use LILO with EZ, install LILO on the linux partition
+ rather than on the master boot record, and then mark the
+ linux partition as "bootable" or "active" using fdisk.
+ (courtesy of Juha Laiho <jlaiho@ichaos.nullnet.fi>).
NEW! - ide-cd.c now compiles separate from ide.c
NEW! - Bus-Master DMA support for Intel PCI Triton chipset IDE interfaces
- for details, see comments at top of triton.c
================================================================================
- from: 'delman@mipg.upenn.edu'
- subject: rz1000
+ 1995 Nov 16 at 08:25 EST
+ from: 'dwhysong@dolphin.physics.ucsb.edu' (BNR400)
+
+[I'm cc'ing this to Mark Lord: FYI, I've got at DTC2278S VLB EIDE
+controller with a Connor CFA850A as /dev/hda and a Maxtor 7213A as
+/dev/hdb using Linux 1.2.13 w/patches for assembly strcpy and the kswap
+patches. I'm getting strange behavior and an unstable system when I try to
+use 32 bit VLB data transfer to the interface card. However, hdparm
+reports that the Connor is extremely fast when I can get the 32 bit mode
+enabled using hdparm -c1 /dev/hd(a|b). However, if I don't do hdparm -c1
+on both /dev/hda and /dev/hdb, then when I run "hdparm -t /dev/hda" the
+disk subsystem locks up... the disk LED comes on and stays on, and no
+other programs are able to get disk access (I can switch VC's, but I can't
+get past the username prompt). I thought you should know about this. I'm
+not sure if it's a problem with the support for the DTC cards, or a
+peculiarity with my hardware configuration. I doubt that my hardware
+itself is flaky, though that's always a possibility.]
+
+On Wed, 15 Nov 1995, Michael Faurot wrote:
+
+> > The trick is setting BOTH drives to use the 32 bit interface.
+>
+> Congrats on getting it going. Those are some great transfer
+> rates. I noticed you did switch on the unmasking. Noticed any
+> problems with things under extreme load or with serial transfers?
+
+I've never had any problems which I could trace to interrupt unmasking.
+Of course, my system usually doesn't have a really heavy load, either.
+These numbers seem way too high for a disk with something like 3500 (?)
+RPM.
+
+Sleepy# hdparm -t /dev/hda
+
+/dev/hda:
+ Timing buffer-cache reads: 32 MB in 2.24 seconds =14.29 MB/sec
+ Timing buffered disk reads: 16 MB in 3.63 seconds = 4.41 MB/sec
+ Estimating raw driver speed: 16 MB in 2.51 seconds = 6.37 MB/sec
+
+> Not sure I was much help to you, but I'm glad to hear you got it
+> working--and pretty impressivly at that. :-)
+
+Mmm, well, about that... I've found that my Connor drive (/dev/hda) is
+pretty fast when I have my system configured like this. I'm still not
+sure I trust the "hdparm -t" results, though. However, when I try
+"hdparm -t /dev/hdb" (/dev/hdb is an older Maxtor 7213A) I have the same
+problem I had before with my disk subsystem locking up.
+
+I've tried just about every possible combination of flags in ide.c and
+hdparm, and I can't get decent performance out of this drive/controller
+combination without some kind of instability creeping in. I'm living with
+the situation now only because /dev/hdb is a DOS-only drive, and I don't
+need it under Linux. However, I don't really like the situation.
+
+-Dave
+dwhysong@physics.ucsb.edu
+
+(Why can't this stuff be simple? Plug the card in, and it works? Every
+hardware manufacturer has to have their own way of doing things...)
-Hi Mark! Looks like you managed to get the info from Intel to disable
-the read-ahead feature of the RZ1000. My encounter with
-Zeos (subsidiary of Micron which owns PCTech) has not been as
-successful --- one guy needs to ask his supervisors about NDA, another
-guy thinks that there is too much of a performance hit with read-ahead
-disabled.
-
-Did the following benchmark to see how true the claim is.
-With Linux 1.2.13, average of 10 "hdparm -t" in MB/s:
-
- hdparm -c0 hdparm -c1
-read-ahead enabled 4.28 4.25
-read-ahead disabled 3.58 4.30
-
-Maybe -c1 should be the default for the RZ1000, or as a suggestion in
-the README for people with the RZ1000.
-
-Cheers, Delman.
--- /dev/null
+/*
+ * linux/drivers/block/cmd640.c Version 0.01 Nov 16, 1995
+ *
+ * Copyright (C) 1995 Linus Torvalds & author (see below)
+ */
+
+/*
+ * Principal Author/Maintainer: abramov@cecmow.enet.dec.com (Igor)
+ *
+ * This file provides support for the advanced features and bugs
+ * of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
+ *
+ * Version 0.01 Initial version, hacked out of ide.c,
+ * and #include'd rather than compiled separately.
+ * This will get cleaned up in a subsequent release.
+ */
+
+/* Interface to access cmd640x registers */
+static void (*put_cmd640_reg)(int key, int reg_no, int val);
+static byte (*get_cmd640_reg)(int key, int reg_no);
+
+enum { none, vlb, pci1, pci2 };
+static int bus_type = none;
+static int cmd640_chip_version;
+static int cmd640_key;
+static byte is_cmd640[MAX_HWIFS];
+
+/*
+ * For some unknown reasons pcibios functions which read and write registers
+ * do not work with cmd640. We use direct io instead.
+ */
+
+/* PCI method 1 access */
+
+static void put_cmd640_reg_pci1(int key, int reg_no, int val)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ outl_p((reg_no & 0xfc) | key, 0xcf8);
+ outb_p(val, (reg_no & 3) + 0xcfc);
+ restore_flags(flags);
+}
+
+static byte get_cmd640_reg_pci1(int key, int reg_no)
+{
+ byte b;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ outl_p((reg_no & 0xfc) | key, 0xcf8);
+ b = inb(0xcfc + (reg_no & 3));
+ restore_flags(flags);
+ return b;
+}
+
+/* PCI method 2 access (from CMD datasheet) */
+
+static void put_cmd640_reg_pci2(int key, int reg_no, int val)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ outb_p(0x10, 0xcf8);
+ outb_p(val, key + reg_no);
+ outb_p(0, 0xcf8);
+ restore_flags(flags);
+}
+
+static byte get_cmd640_reg_pci2(int key, int reg_no)
+{
+ byte b;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ outb_p(0x10, 0xcf8);
+ b = inb(key + reg_no);
+ outb_p(0, 0xcf8);
+ restore_flags(flags);
+ return b;
+}
+
+/* VLB access */
+
+static void put_cmd640_reg_vlb(int key, int reg_no, int val)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ outb(reg_no, key + 8);
+ outb(val, key + 0xc);
+ restore_flags(flags);
+}
+
+static byte get_cmd640_reg_vlb(int key, int reg_no)
+{
+ byte b;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ outb(reg_no, key + 8);
+ b = inb(key + 0xc);
+ restore_flags(flags);
+ return b;
+}
+
+/*
+ * Probe for CMD640x -- pci method 1
+ */
+
+static int probe_for_cmd640_pci1(void)
+{
+ long id;
+ int k;
+
+ for (k = 0x80000000; k <= 0x8000f800; k += 0x800) {
+ outl(k, 0xcf8);
+ id = inl(0xcfc);
+ if (id != 0x06401095)
+ continue;
+ put_cmd640_reg = put_cmd640_reg_pci1;
+ get_cmd640_reg = get_cmd640_reg_pci1;
+ cmd640_key = k;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Probe for CMD640x -- pci method 2
+ */
+
+static int probe_for_cmd640_pci2(void)
+{
+ int i;
+ int v_id;
+ int d_id;
+
+ for (i = 0xc000; i <= 0xcf00; i += 0x100) {
+ outb(0x10, 0xcf8);
+ v_id = inw(i);
+ d_id = inw(i + 2);
+ outb(0, 0xcf8);
+ if (v_id != 0x1095 || d_id != 0x640)
+ continue;
+ put_cmd640_reg = put_cmd640_reg_pci2;
+ get_cmd640_reg = get_cmd640_reg_pci2;
+ cmd640_key = i;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Probe for CMD640x -- vlb
+ */
+
+static int probe_for_cmd640_vlb(void) {
+ byte b;
+
+ outb(0x50, 0x178);
+ b = inb(0x17c);
+ if (b == 0xff || b == 0 || (b & 0x20)) {
+ outb(0x50, 0xc78);
+ b = inb(0x7c);
+ if (b == 0xff || b == 0 || !(b & 0x20))
+ return 0;
+ cmd640_key = 0x70;
+ } else {
+ cmd640_key = 0x170;
+ }
+ put_cmd640_reg = put_cmd640_reg_vlb;
+ get_cmd640_reg = get_cmd640_reg_vlb;
+ return 1;
+}
+
+/*
+ * Probe for Cmd640x and initialize it if found
+ */
+
+int ide_probe_for_cmd640x(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_HWIFS; i++)
+ is_cmd640[i] = 0;
+
+ if (probe_for_cmd640_pci1()) {
+ bus_type = pci1;
+ } else if (probe_for_cmd640_pci2()) {
+ bus_type = pci2;
+ } else if (cmd640_vlb && probe_for_cmd640_vlb()) {
+ /* May be remove cmd640_vlb at all, and probe in any case */
+ bus_type = vlb;
+ } else {
+ return 0;
+ }
+
+ /*
+ * Undocumented magic. (There is no 0x5b port in specs)
+ */
+
+ put_cmd640_reg(cmd640_key, 0x5b, 0xbd);
+ if (get_cmd640_reg(cmd640_key, 0x5b) != 0xbd) {
+ printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n");
+ return 0;
+ }
+ put_cmd640_reg(cmd640_key, 0x5b, 0);
+
+ /*
+ * Documented magic.
+ */
+
+ cmd640_chip_version = get_cmd640_reg(cmd640_key, 0x50) & 3;
+ if (cmd640_chip_version == 0) {
+ printk ("ide: wrong CMD640 version -- 0\n");
+ return 0;
+ }
+
+ put_cmd640_reg(cmd640_key, 0x51, get_cmd640_reg(cmd640_key, 0x51) | 0xc8);
+ put_cmd640_reg(cmd640_key, 0x57, 0);
+ put_cmd640_reg(cmd640_key, 0x57, get_cmd640_reg(cmd640_key, 0x57) | 0x0c);
+
+ serialized = 1;
+
+ printk("ide: buggy CMD640 interface at ");
+ switch (bus_type) {
+ case vlb :
+ printk("local bus, port 0x%x", cmd640_key);
+ break;
+ case pci1:
+ printk("pci, (0x%x)", cmd640_key);
+ break;
+ case pci2:
+ printk("pci,(access method 2) (0x%x)", cmd640_key);
+ break;
+ }
+
+ is_cmd640[0] = is_cmd640[1] = 1;
+
+ /*
+ * Reset interface timings
+ */
+
+ put_cmd640_reg(cmd640_key, 0x58, 0);
+ put_cmd640_reg(cmd640_key, 0x52, 0);
+
+ printk("\n ... serialized, disabled read-ahead, secondary interface enabled\n");
+
+ return 1;
+}
+
+static int as_clocks(int a) {
+ switch (a & 0xf0) {
+ case 0 : return 4;
+ case 0x40 : return 2;
+ case 0x80 : return 3;
+ case 0xc0 : return 5;
+ default : return -1;
+ }
+}
+
+/*
+ * Tuning of drive parameters
+ */
+
+static void cmd640_set_timing(int if_num, int dr_num, int r1, int r2) {
+ int b_reg;
+ byte b;
+ int r52;
+
+ b_reg = if_num ? 0x57 : dr_num ? 0x55 : 0x53;
+
+ if (if_num == 0) {
+ put_cmd640_reg(cmd640_key, b_reg, r1);
+ put_cmd640_reg(cmd640_key, b_reg + 1, r2);
+ } else {
+ b = get_cmd640_reg(cmd640_key, b_reg);
+ if ((b&1) == 0) {
+ put_cmd640_reg(cmd640_key, b_reg, r1);
+ } else {
+ if (as_clocks(b) < as_clocks(r1))
+ put_cmd640_reg(cmd640_key, b_reg, r1);
+ }
+ b = get_cmd640_reg(cmd640_key, b_reg + 1);
+ if (b == 0) {
+ put_cmd640_reg(cmd640_key, b_reg + 1, r2);
+ } else {
+ r52 = (b&0xf) < (r2&0xf) ? (r2&0xf) : (b&0xf);
+ r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0);
+ put_cmd640_reg(cmd640_key, b_reg+1, r52);
+ }
+ }
+
+ b = get_cmd640_reg(cmd640_key, 0x52);
+ if (b == 0) {
+ put_cmd640_reg(cmd640_key, 0x52, r2);
+ } else {
+ r52 = (b&0xf) < (r2&0xf) ? (r2&0xf) : (b&0xf);
+ r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0);
+ put_cmd640_reg(cmd640_key, 0x52, r52);
+ }
+}
+
+static int bus_speed = 33; /* MHz */
+
+struct pio_timing {
+ int mc_time; /* Minimal cycle time (ns) */
+ int av_time; /* Address valid to DIOR-/DIOW- setup (ns) */
+ int ds_time; /* DIOR data setup (ns) */
+} pio_timings[6] = {
+ { 70, 165, 600 }, /* PIO Mode 0 */
+ { 50, 125, 383 }, /* PIO Mode 1 */
+ { 30, 100, 240 }, /* PIO Mode 2 */
+ { 30, 80, 180 }, /* PIO Mode 3 */
+ { 25, 70, 125 }, /* PIO Mode 4 */
+ { 20, 50, 100 } /* PIO Mode ? */
+};
+
+struct drive_pio_info {
+ const char *name;
+ int pio;
+} drive_pios[] = {
+ { "Maxtor 7131 AT", 1 },
+ { "Maxtor 7171 AT", 1 },
+ { "Maxtor 7213 AT", 1 },
+ { "Maxtor 7245 AT", 1 },
+ { "SAMSUNG SHD-3122A", 1 },
+ { "QUANTUM ELS127A", 0 },
+ { "QUANTUM LPS240A", 0 },
+ { "QUANTUM LPS270A", 3 },
+ { "QUANTUM LPS540A", 3 },
+ { NULL, 0 }
+};
+
+static int known_drive_pio(char* name) {
+ struct drive_pio_info* pi;
+
+ for (pi = drive_pios; pi->name != NULL; pi++) {
+ if (strcmp(pi->name, name) == 0)
+ return pi->pio;
+ }
+ return -1;
+}
+
+static void cmd640_timings_to_regvals(int mc_time, int av_time, int ds_time,
+ int clock_time,
+ int* r1, int* r2)
+{
+ int a, b;
+
+ a = (mc_time + clock_time - 1)/clock_time;
+ if (a <= 2) *r1 = 0x40;
+ else if (a == 3) *r1 = 0x80;
+ else if (a == 4) *r1 = 0;
+ else *r1 = 0xc0;
+
+ a = (av_time + clock_time - 1)/clock_time;
+ if (a < 2)
+ a = 2;
+ b = (ds_time + clock_time - 1)/clock_time - a;
+ if (b < 2)
+ b = 2;
+ if (b > 0x11) {
+ a += b - 0x11;
+ b = 0x11;
+ }
+ if (a > 0xf)
+ a = 0;
+ if (cmd640_chip_version > 1)
+ b -= 1;
+ if (b > 0xf)
+ b = 0;
+ *r2 = (a << 4) | b;
+}
+
+static void set_pio_mode(int if_num, int drv_num, int mode_num) {
+ int p_base;
+ int i;
+
+ p_base = if_num ? 0x170 : 0x1f0;
+ outb(3, p_base + 1);
+ outb(mode_num | 8, p_base + 2);
+ outb((drv_num | 0xa) << 4, p_base + 6);
+ outb(0xef, p_base + 7);
+ for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++)
+ delay_10ms();
+}
+
+void cmd640_tune_drive(ide_drive_t* drive) {
+ int interface_number;
+ int drive_number;
+ int clock_time; /* ns */
+ int max_pio;
+ int mc_time, av_time, ds_time;
+ struct hd_driveid* id;
+ int r1, r2;
+
+ /*
+ * Determine if drive is under cmd640 control
+ */
+ interface_number = HWIF(drive) - ide_hwifs;
+ if (!is_cmd640[interface_number])
+ return;
+
+ drive_number = drive - HWIF(drive)->drives;
+ clock_time = 1000/bus_speed;
+ id = drive->id;
+ if ((max_pio = known_drive_pio(id->model)) != -1) {
+ mc_time = pio_timings[max_pio].mc_time;
+ av_time = pio_timings[max_pio].av_time;
+ ds_time = pio_timings[max_pio].ds_time;
+ } else {
+ max_pio = id->tPIO;
+ mc_time = pio_timings[max_pio].mc_time;
+ av_time = pio_timings[max_pio].av_time;
+ ds_time = pio_timings[max_pio].ds_time;
+ if (id->field_valid & 2) {
+ if ((id->capability & 8) && (id->eide_pio_modes & 7)) {
+ if (id->eide_pio_modes & 4) max_pio = 5;
+ else if (id->eide_pio_modes & 2) max_pio = 4;
+ else max_pio = 3;
+ ds_time = id->eide_pio_iordy;
+ mc_time = pio_timings[max_pio].mc_time;
+ av_time = pio_timings[max_pio].av_time;
+ } else {
+ ds_time = id->eide_pio;
+ }
+ if (ds_time == 0)
+ ds_time = pio_timings[max_pio].ds_time;
+ }
+ }
+ cmd640_timings_to_regvals(mc_time, av_time, ds_time, clock_time,
+ &r1, &r2);
+ set_pio_mode(interface_number, drive_number, max_pio);
+ cmd640_set_timing(interface_number, drive_number, r1, r2);
+ printk ("Mode and Timing set to PIO%d (0x%x 0x%x)\n", max_pio, r1, r2);
+}
{
unsigned char perp_mode;
- if (!floppy)
- return;
- if (floppy->rate & 0x40){
- switch(raw_cmd->rate){
+ if (raw_cmd->rate & 0x40){
+ switch(raw_cmd->rate & 3){
case 0:
perp_mode=2;
break;
static int fdc_dtr(void)
{
/* If data rate not already set to desired value, set it. */
- if (raw_cmd->rate == FDCS->dtr)
+ if ((raw_cmd->rate & 3) == FDCS->dtr)
return 0;
/* Set dtr */
- fd_outb(raw_cmd->rate, FD_DCR);
+ fd_outb(raw_cmd->rate & 3, FD_DCR);
/* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
* need a stabilization period of several milliseconds to be
* enforced after data rate changes before R/W operations.
* Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
*/
- FDCS->dtr = raw_cmd->rate;
+ FDCS->dtr = raw_cmd->rate & 3;
return(wait_for_completion(jiffies+2*HZ/100,
(timeout_fn) floppy_ready));
} /* fdc_dtr */
raw_cmd->flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
/*FD_RAW_NEED_DISK |*/ FD_RAW_NEED_SEEK;
- raw_cmd->rate = floppy->rate & 0x3;
+ raw_cmd->rate = floppy->rate & 0x43;
raw_cmd->cmd_count = NR_F;
COMMAND = FM_MODE(floppy,FD_FORMAT);
DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,format_req.head);
SIZECODE = 2;
} else
SIZECODE = FD_SIZECODE(floppy);
- raw_cmd->rate = floppy->rate & 3;
+ raw_cmd->rate = floppy->rate & 0x43;
if ((floppy->rate & FD_2M) &&
(TRACK || HEAD) &&
raw_cmd->rate == 2)
rcmd = & (ptr->next);
if (!(ptr->flags & FD_RAW_MORE))
return 0;
- ptr->rate &= 0x03;
+ ptr->rate &= 0x43;
}
}
/*
- * linux/drivers/block/ide.c Version 5.17 Nov 3, 1995
+ * linux/drivers/block/ide.c Version 5.18 Nov 16, 1995
*
* Copyright (C) 1994, 1995 Linus Torvalds & authors (see below)
*/
/*
- * This is the multiple IDE interface driver, as evolved from hd.c.
+ * This is the multiple IDE interface driver, as evolved from hd.c.
* It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
* There can be up to two drives per interface, as per the ATA-2 spec.
*
* Secondary i/f: ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
* Tertiary i/f: ide2: major=33; (hde) minor=0; (hdf) minor=64
* Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64
- *
+ *
* It is easy to extend ide.c to handle more than four interfaces:
*
* Change the MAX_HWIFS constant in ide.h.
- *
+ *
* Define some new major numbers (in major.h), and insert them into
* the ide_hwif_to_major table in ide.c.
- *
+ *
* Fill in the extra values for the new interfaces into the two tables
* inside ide.c: default_io_base[] and default_irqs[].
- *
+ *
* Create the new request handlers by cloning "do_ide3_request()"
* for each new interface, and add them to the switch statement
* in the ide_init() function in ide.c.
* Maintained by Mark Lord (mlord@bnr.ca): ide.c, ide.h, triton.c, hd.c, ..
*
* This was a rewrite of just about everything from hd.c, though some original
- * code is still sprinkled about. Think of it as a major evolution, with
+ * code is still sprinkled about. Think of it as a major evolution, with
* inspiration from lots of linux users, esp. hamish@zot.apana.org.au
*
* Version 1.0 ALPHA initial code, primary i/f working okay
* remove "Huh?" from cmd640 code
* added qd6580 interface speed select from Colten Edwards
* Version 5.17 kludge around bug in BIOS32 on Intel triton motherboards
+ * Version 5.18 new CMD640 code, moved to cmd640.c, #include'd for now
+ * new UMC8672 code, moved to umc8672.c, #include'd for now
+ * disallow turning on DMA when h/w not capable of DMA
*
* Driver compile-time options are in ide.h
*
* To do, in likely order of completion:
+ * - make cmd640.c and umc8672.c compile separately from ide.c
* - add ALI M1443/1445 chipset support from derekn@vw.ece.cmu.edu
- * - add Promise Caching controller support from peterd@pnd-pc.demon.co.uk
* - add ioctls to get/set interface timings on various interfaces
+ * - add Promise Caching controller support from peterd@pnd-pc.demon.co.uk
* - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- * - improved CMD support: handed this off to someone else
* - find someone to work on IDE *tape drive* support
*/
#include "ide.h"
+#ifdef SUPPORT_CMD640
+void cmd640_tune_drive(ide_drive_t *);
+static int cmd640_vlb = 0;
+#endif
+
ide_hwif_t ide_hwifs[MAX_HWIFS]; /* hwif info */
static ide_hwgroup_t *irq_to_hwgroup [16];
-static const byte ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
+static const byte ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168};
static const byte default_irqs[MAX_HWIFS] = {14, 15, 11, 10};
/*
* multwrite() transfers a block of one or more sectors of data to a drive
- * as part of a disk multwrite operation.
+ * as part of a disk multwrite operation.
*/
static void multwrite (ide_drive_t *drive)
{
if (drive->select.b.lba) {
#ifdef DEBUG
printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
- drive->name, (rq->cmd==READ)?"read":"writ",
+ drive->name, (rq->cmd==READ)?"read":"writ",
block, rq->nr_sectors, (unsigned long) rq->buffer);
#endif
OUT_BYTE(block,io_base+IDE_SECTOR_OFFSET);
printk("%s: marginal timeout\n", drive->name);
} else { /* drive not responding */
hwgroup->handler = NULL;
- if (hwgroup->hwif->dmaproc)
+ if (hwgroup->hwif->dmaproc)
(void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
if (!ide_error(drive, "irq timeout", GET_STAT()))
do_hwgroup_request (hwgroup);
* In reality, this is a non-issue. The new command is not sent unless the
* drive is ready to accept one, in which case we know the drive is not
* trying to interrupt us. And ide_set_handler() is always invoked before
- * completing the issuance of any new drive command, so we will not be
+ * completing the issuance of any new drive command, so we will not be
* accidently invoked as a result of any valid command completion interrupt.
*
*/
case BLKRAGET:
return write_fs_long(arg, read_ahead[MAJOR(inode->i_rdev)]);
- case BLKGETSIZE: /* Return device size */
+ case BLKGETSIZE: /* Return device size */
return write_fs_long(arg, drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects);
case BLKRRPART: /* Re-read partition tables */
return revalidate_disk(inode->i_rdev);
- case HDIO_GET_KEEPSETTINGS:
+ case HDIO_GET_KEEPSETTINGS:
return write_fs_long(arg, drive->keep_settings);
- case HDIO_GET_UNMASKINTR:
+ case HDIO_GET_UNMASKINTR:
return write_fs_long(arg, drive->unmask);
- case HDIO_GET_DMA:
+ case HDIO_GET_DMA:
return write_fs_long(arg, drive->using_dma);
- case HDIO_GET_CHIPSET:
+ case HDIO_GET_CHIPSET:
return write_fs_long(arg, drive->chipset);
- case HDIO_GET_MULTCOUNT:
+ case HDIO_GET_MULTCOUNT:
return write_fs_long(arg, drive->mult_count);
case HDIO_GET_IDENTITY:
cli();
switch (cmd) {
case HDIO_SET_DMA:
+ if (!(HWIF(drive)->dmaproc)) {
+ restore_flags(flags);
+ return -EPERM;
+ }
drive->using_dma = arg;
break;
case HDIO_SET_KEEPSETTINGS:
drive->present = 1;
drive->cyl = drive->bios_cyl = id->cyls;
drive->head = drive->bios_head = id->heads;
- drive->sect = drive->bios_sect = id->sectors;
+ drive->sect = drive->bios_sect = id->sectors;
}
/* Handle logical geometry translation by the drive */
if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads
/*
* Extract the physical drive geometry for our use.
* Note that we purposely do *not* update the bios info.
- * This way, programs that use it (like fdisk) will
+ * This way, programs that use it (like fdisk) will
* still have the same logical view as the BIOS does,
* which keeps the partition table from being screwed.
*
if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) {
drive->cyl = id->cyls;
drive->head = id->heads;
- drive->sect = id->sectors;
+ drive->sect = id->sectors;
}
/* Correct the number of cyls if the bios value is too small */
if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
printk(", DMA");
}
printk("\n");
+#ifdef SUPPORT_CMD640
+ cmd640_tune_drive(drive); /* but can we tune a fish? */
+#endif
}
/*
* The code enables the secondary IDE controller and the PIO4 (3?) timings on
* the primary (EIDE). You may probably have to enable the 32-bit support to
* get the full speed. You better get the disk interrupts disabled ( hdparm -u0
- * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
- * filesystem corrupted with -u1, but under heavy disk load only :-)
+ * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
+ * filesystem corrupted with -u1, but under heavy disk load only :-)
*
* From: mlord@bnr.ca -- this chipset is now forced to use the "serialize" feature,
* which hopefully will make it more reliable to use.. maybe it has the same bugs
}
#endif /* SUPPORT_QD6580 */
-#if SUPPORT_CMD640
-/*
- * ??? fixme:
- */
-byte read_cmd640_vlb (byte port, byte reg)
-{
- byte val;
-
- unsigned long flags;
- save_flags(flags);
- cli();
- outw(reg, port);
- val = inb(port+4);
- restore_flags(flags);
- return val;
-}
-
-void write_cmd640_vlb (byte port, byte reg, byte val)
-{
- unsigned long flags;
- save_flags(flags);
- cli();
- outw(reg, port);
- outw(val, port+4);
- restore_flags(flags);
-}
-
-void init_cmd640_vlb (void)
-{
- byte reg;
- unsigned short port = 0x178;
-
- serialized = 1;
- printk("ide: buggy CMD640 interface: serialized, ");
- reg = read_cmd640_vlb(port, 0x50);
- if (reg == 0xff || (reg & 0x90) != 0x90) {
-#if TRY_CMD640_VLB_AT_0x78
- port = 0x78;
- reg = read_cmd640_vlb(port, 0x50);
- if (reg == 0xff || (reg & 0x90) != 0x90)
+#ifdef SUPPORT_UMC8672
+#include "umc8672.c" /* until we tidy up the interface some more */
#endif
- {
- disallow_unmask = 1;
- printk("(probe failed) disabled unmasking\n");
- return;
- }
- }
- write_cmd640_vlb(port, 0x51, read_cmd640_vlb(port, 0x51)|0xc8);
- write_cmd640_vlb(port, 0x57, read_cmd640_vlb(port, 0x57)|0x0c);
- printk("disabled read-ahead, enabled secondary\n");
-}
-#endif /* SUPPORT_CMD640 */
+#ifdef SUPPORT_CMD640
+#include "cmd640.c" /* until we tidy up the interface some more */
+#endif
/*
* stridx() returns the offset of c within s,
* 2. if the remainder matches one of the supplied keywords,
* the index (1 based) of the keyword is negated and returned.
* 3. if the remainder is a series of no more than max_vals numbers
- * separated by commas, the numbers are saved in vals[] and a
+ * separated by commas, the numbers are saved in vals[] and a
* count of how many were saved is returned. Base10 is assumed,
* and base16 is allowed when prefixed with "0x".
* 4. otherwise, zero is returned.
/*
* Look for a series of no more than "max_vals"
* numeric values separated by commas, in base10,
- * or base16 when prefixed with "0x".
+ * or base16 when prefixed with "0x".
* Return a count of how many were found.
*/
for (n = 0; (i = stridx(decimal, *s)) >= 0;) {
* Look for interface options: "idex="
*/
if (s[0] == 'i' && s[1] == 'd' && s[2] == 'e' && s[3] >= '0' && s[3] <= max_hwif) {
- const char *ide_words[] = {"noprobe", "serialize", "dtc2278", "ht6560b", "cmd640_vlb", "qd6580", NULL};
+ const char *ide_words[] = {"noprobe", "serialize", "dtc2278", "ht6560b",
+ "cmd640_vlb", "qd6580", "umc8672", NULL};
hw = s[3] - '0';
hwif = &ide_hwifs[hw];
switch (match_parm(&s[4], ide_words, vals, 3)) {
+#if SUPPORT_UMC8672
+ case -7: /* "umc8672" */
+ if (hw != 0) goto bad_hwif;
+ init_umc8672();
+ goto done;
+#endif /* SUPPORT_UMC8672 */
#if SUPPORT_QD6580
case -6: /* "qd6580" */
if (hw != 0) goto bad_hwif;
#if SUPPORT_CMD640
case -5: /* "cmd640_vlb" */
if (hw > 1) goto bad_hwif;
- init_cmd640_vlb();
- goto do_serialize; /* not necessary once we implement the above */
+ cmd640_vlb = 1;
break;
#endif /* SUPPORT_CMD640 */
#if SUPPORT_HT6560B
drive->cyl = drive->bios_cyl = drive->id->cyls;
drive->head = drive->bios_head = drive->id->heads;
- drive->sect = drive->bios_sect = drive->id->sectors;
+ drive->sect = drive->bios_sect = drive->id->sectors;
drive->special.b.set_geometry = 1;
tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
* drives in the system -- the ones reflected as drive 1 or 2. The first
* drive is stored in the high nibble of CMOS byte 0x12, the second in the low
* nibble. This will be either a 4 bit drive type or 0xf indicating use byte
- * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value
+ * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value
* means we have an AT controller hard disk for that drive.
*
* Of course, there is no guarantee that either drive is actually on the
}
#endif /* SUPPORT_RZ1000 */
-#if SUPPORT_CMD640
-void init_cmd640 (byte bus, byte fn)
-{
- int rc;
- unsigned char reg;
-
- serialized = 1;
- printk("ide: buggy CMD640 interface: ");
-
-#if 0 /* funny.. the cmd640b I tried this on claimed to not be enabled.. */
- unsigned short sreg;
- if ((rc = pcibios_read_config_word (bus, fn, PCI_COMMAND, &sreg))) {
- ide_pci_access_error (rc);
- } else if (!(sreg & 1)) {
- printk("not enabled\n");
- } else {
-
- /*
- * The first part is undocumented magic from the DOS driver.
- * According to the datasheet, there is no port 0x5b on the cmd640.
- */
- (void) pcibios_write_config_byte(bus, fn, 0x5b, 0xbd);
- if (pcibios_write_config_byte(bus, fn, 0x5b, 0xbd) != 0xbd)
- printk("init_cmd640: huh? 0x5b read back wrong\n");
- (void) pcibios_write_config_byte(bus, fn, 0x5b, 0);
-#endif /* 0 */
- /*
- * The rest is from the cmd640b datasheet.
- */
- if ((rc = pcibios_read_config_byte(bus, fn, 0x51, ®))
- || (rc = pcibios_write_config_byte(bus, fn, 0x51, reg | 0xc0)) /* 0xc8 to enable 2nd i/f */
- || (rc = pcibios_read_config_byte(bus, fn, 0x57, ®))
- || (rc = pcibios_write_config_byte(bus, fn, 0x57, reg | 0x0c)))
- buggy_interface_fallback (rc);
- else
- printk("serialized, disabled read-ahead\n");
-}
-#endif /* SUPPORT_CMD640 */
-
typedef void (ide_pci_init_proc_t)(byte, byte);
/*
/*
* ide_init_pci() finds/initializes "known" PCI IDE interfaces
- *
+ *
* This routine should ideally be using pcibios_find_class() to find
* all IDE interfaces, but that function causes some systems to "go weird".
*/
#if SUPPORT_RZ1000
ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, &init_rz1000, 0);
#endif
-#if SUPPORT_CMD640
- ide_probe_pci (PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640, &init_cmd640, 0);
-#endif
#ifdef CONFIG_BLK_DEV_TRITON
/*
* Apparently the BIOS32 services on Intel motherboards are buggy,
if (pcibios_present())
ide_init_pci ();
#endif /* CONFIG_PCI */
+#ifdef SUPPORT_CMD640
+ ide_probe_for_cmd640x();
+#endif
/*
* Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
#ifndef SUPPORT_CMD640 /* 1 to support CMD640 chipset */
#define SUPPORT_CMD640 1 /* 0 to reduce kernel size */
#endif
+#ifndef SUPPORT_UMC8672 /* 1 to support UMC8672 chipset */
+#define SUPPORT_UMC8672 1 /* 0 to reduce kernel size */
+#endif
#ifndef SUPPORT_HT6560B /* 1 to support HT6560B chipset */
#define SUPPORT_HT6560B 1 /* 0 to reduce kernel size */
#endif
else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
}
+static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, short disk_index)
+{
+ kstat.dk_drive[disk_index]++;
+ if (cmd == READ || cmd == READA) {
+ kstat.dk_drive_rio[disk_index]++;
+ kstat.dk_drive_rblk[disk_index] += nr_sectors;
+ }
+ else if (cmd == WRITE || cmd == WRITEA) {
+ kstat.dk_drive_wio[disk_index]++;
+ kstat.dk_drive_wblk[disk_index] += nr_sectors;
+ }
+}
+
/*
* add-request adds a request to the linked list.
* It disables interrupts so that it can muck with the
case SCSI_DISK_MAJOR:
disk_index = (MINOR(req->rq_dev) & 0x0070) >> 4;
if (disk_index < 4)
- kstat.dk_drive[disk_index]++;
+ drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
break;
case IDE0_MAJOR: /* same as HD_MAJOR */
case XT_DISK_MAJOR:
disk_index = (MINOR(req->rq_dev) & 0x0040) >> 6;
- kstat.dk_drive[disk_index]++;
+ drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
break;
case IDE1_MAJOR:
disk_index = ((MINOR(req->rq_dev) & 0x0040) >> 6) + 2;
- kstat.dk_drive[disk_index]++;
+ drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
default:
break;
}
/*
- * linux/drivers/block/triton.c Version 1.02 Oct 13, 1995
+ * linux/drivers/block/triton.c Version 1.03 Nov 16, 1995
*
* Copyright (c) 1995 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
* the observation that WRITEs work most of the time, depending on
* cache-buffer occupancy, but multi-sector reads seldom work.
*
- * Drives like the AC31000H could likely be made to work if all DMA were done
- * one sector at a time, but that would likely negate any advantage over PIO.
+ * Testing was done with a Gigabyte GA-586 ATE system and the following drive:
+ * (Uwe Bonnes - bon@elektron.ikp.physik.th-darmstadt.de)
+ *
+ * Western Digital AC31600H (1.6Gig w/128kB buffer), DMA mode2, PIO mode4.
+ * - much better than its 1Gig cousin, this drive is reported to work
+ * very well with DMA (7.3MB/sec).
*
* If you have any drive models to add, email your results to: mlord@bnr.ca
* Keep an eye on /var/adm/messages for "DMA disabled" messages.
--- /dev/null
+/*
+ * linux/drivers/block/umc8672.c Version 0.01 Nov 16, 1995
+ *
+ * Copyright (C) 1995 Linus Torvalds & author (see below)
+ */
+
+/*
+ * Principal Author/Maintainer: PODIEN@hml2.atlas.de (Wolfram Podien)
+ *
+ * This file provides support for the advanced features
+ * of the UMC 8672 IDE interface.
+ *
+ * Version 0.01 Initial version, hacked out of ide.c,
+ * and #include'd rather than compiled separately.
+ * This will get cleaned up in a subsequent release.
+ */
+
+/*
+ * VLB Controller Support from
+ * Wolfram Podien
+ * Rohoefe 3
+ * D28832 Achim
+ * Germany
+ *
+ * To enable UMC8672 support there must a lilo line like
+ * append="hd=umc8672"...
+ * To set the speed according to the abilities of the hardware there must be a
+ * line like
+ * #define UMC_DRIVE0 11
+ * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
+ * are some lines present). 0 - 11 are allowed speed values. These values are
+ * the results from the DOS speed test programm supplied from UMC. 11 is the
+ * highest speed (about PIO mode 3)
+ */
+
+/*
+ * The speeds will eventually become selectable using hdparm via ioctl's,
+ * but for now they are coded here:
+ */
+#define UMC_DRIVE0 11 /* DOS messured drive Speeds */
+#define UMC_DRIVE1 11 /* 0 - 11 allowed */
+#define UMC_DRIVE2 11 /* 11 = Highest Speed */
+#define UMC_DRIVE3 11 /* In case of crash reduce speed */
+
+void out_umc (char port,char wert)
+{
+ outb_p (port,0x108);
+ outb_p (wert,0x109);
+}
+
+byte in_umc (char port)
+{
+ outb_p (port,0x108);
+ return inb_p (0x109);
+}
+
+void init_umc8672(void)
+{
+ int i,tmp;
+ int speed [4];
+/* 0 1 2 3 4 5 6 7 8 9 10 11 */
+ char speedtab [3][12] = {
+ {0xf ,0xb ,0x2 ,0x2 ,0x2 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 },
+ {0x3 ,0x2 ,0x2 ,0x2 ,0x2 ,0x2 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 },
+ {0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
+
+ cli ();
+ outb_p (0x5A,0x108); /* enable umc */
+ if (in_umc (0xd5) != 0xa0)
+ {
+ sti ();
+ printk ("UMC8672 not found\n");
+ return;
+ }
+ speed[0] = UMC_DRIVE0;
+ speed[1] = UMC_DRIVE1;
+ speed[2] = UMC_DRIVE2;
+ speed[3] = UMC_DRIVE3;
+ for (i = 0;i < 4;i++)
+ {
+ if ((speed[i] < 0) || (speed[i] > 11))
+ {
+ sti ();
+ printk ("UMC 8672 drive speed out of range. Drive %d Speed %d\n",
+ i, speed[i]);
+ printk ("UMC support aborted\n");
+ return;
+ }
+ }
+ out_umc (0xd7,(speedtab[0][speed[2]] | (speedtab[0][speed[3]]<<4)));
+ out_umc (0xd6,(speedtab[0][speed[0]] | (speedtab[0][speed[1]]<<4)));
+ tmp = 0;
+ for (i = 3; i >= 0; i--)
+ {
+ tmp = (tmp << 2) | speedtab[1][speed[i]];
+ }
+ out_umc (0xdc,tmp);
+ for (i = 0;i < 4; i++)
+ {
+ out_umc (0xd0+i,speedtab[2][speed[i]]);
+ out_umc (0xd8+i,speedtab[2][speed[i]]);
+ }
+ outb_p (0xa5,0x108); /* disable umc */
+ sti ();
+ printk ("Speeds for UMC8672 \n");
+ for (i = 0;i < 4;i++)
+ printk ("Drive %d speed %d\n",i,speed[i]);
+}
*/
-
#include <linux/module.h>
-#ifdef MODULE
-#define mcd_init init_module
-#endif
-
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#define MAJOR_NR MITSUMI_CDROM_MAJOR
#include <linux/blk.h>
+
#define mcd_port mcd /* for compatible parameter passing with "insmod" */
#include <linux/mcd.h>
#endif
/* #define DOUBLE_QUICK_ONLY */
-#if LINUX_VERSION_CODE < 66338
- #define CURRENT_VALID \
- (CURRENT && MAJOR(CURRENT -> dev) == MAJOR_NR && CURRENT -> cmd == READ \
- && CURRENT -> sector != -1)
-#else
- #define CURRENT_VALID \
- (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
- && CURRENT -> sector != -1)
-#endif
+#define CURRENT_VALID \
+(CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
+&& CURRENT -> sector != -1)
+
#define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
#define MCD_BUF_SIZ 16
static volatile int mcd_transfer_is_active;
static int
-#if LINUX_VERSION_CODE < 66338
-check_mcd_change(dev_t full_dev)
-#else
check_mcd_change(kdev_t full_dev)
-#endif
{
int retval, target;
* Test for presence of drive and initialize it. Called at boot time.
*/
-int
-mcd_init(void)
+int mcd_init(void)
{
int count;
unsigned char result[3];
}
#ifdef MODULE
+int init_module(void)
+{
+ return mcd_init();
+}
+
void cleanup_module(void)
{ if (MOD_IN_USE)
{ printk("mcd module in use - can't remove it.\n");
/*
* The Mitsumi CDROM interface
* Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.3
+ * VERSION: 1.5
*
* 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
#if RCS
static const char *mcdx_c_version
- = "mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp";
+ = "mcdx.c,v 1.19 1995/11/20 17:06:25 heiko Exp";
#endif
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/major.h>
-
-/* old kernel (doesn't know about MCDX) */
-#ifndef MITSUMI_X_CDROM_MAJOR
-#define MITSUMI_X_CDROM_MAJOR 20
-#define DEVICE_NAME "mcdx"
-
-/* #define DEVICE_INTR do_mcdx */
-#define DEVICE_REQUEST do_mcdx_request
-#define DEVICE_NR(device) (MINOR(device))
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-#endif
-
#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
#include <linux/blk.h>
changed elsewhere. */
/* declared in blk.h */
-#if LINUX_VERSION_CODE < 66338
-unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end);
-#else
int mcdx_init(void);
-#endif
void do_mcdx_request(void);
-
-#if LINUX_VERSION_CODE < 66338
-int check_mcdx_media_change(dev_t);
-#else
int check_mcdx_media_change(kdev_t);
-#endif
/* already declared in init/main */
void mcdx_setup(char *, int *);
TRACE((REQUEST, "do_request()\n"));
-#if LINUX_VERSION_CODE < 66338
- if ((CURRENT == NULL) || (CURRENT->dev < 0)) {
-#else
if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE)) {
-#endif
TRACE((REQUEST, "do_request() done\n"));
return;
}
-#if LINUX_VERSION_CODE < 66338
- stuffp = mcdx_stuffp[MINOR(CURRENT->dev)];
-#else
stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)];
-#endif
TRACE((REQUEST, "do_request() stuffp = %p\n", stuffp));
INIT_REQUEST;
-#if LINUX_VERSION_CODE < 66338
- dev = MINOR(CURRENT->dev);
-#else
dev = MINOR(CURRENT->rq_dev);
-#endif
if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp->present)) {
-#if LINUX_VERSION_CODE < 66338
- WARN(("do_request(): bad device: 0x%04x\n", CURRENT->dev));
-#else
WARN(("do_request(): bad device: %s\n",
kdevname(CURRENT->rq_dev)));
-#endif
end_request(0);
goto again;
}
return;
}
-#if LINUX_VERSION_CODE < 66338
-int check_mcdx_media_change(dev_t full_dev)
-#else
int check_mcdx_media_change(kdev_t full_dev)
-#endif
/* Return: 1 if media changed since last call to
this function
0 else
Setting flag to 0 resets the changed state. */
{
-#if LINUX_VERSION_CODE < 66338
- INFO(("check_mcdx_media_change called for device %x\n",
- full_dev));
-#else
INFO(("check_mcdx_media_change called for device %s\n",
kdevname(full_dev)));
-#endif
return 0;
}
int i;
int drives = 0;
-#if LINUX_VERSION_CODE < 66338
- mcdx_init(0, 0);
-#else
mcdx_init();
-#endif
for (i = 0; i < MCDX_NDRIVES; i++) {
if (mcdx_stuffp[i]) {
TRACE((INIT, "init_module() drive %d stuff @ %p\n",
}
-#if LINUX_VERSION_CODE < 66338
-unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end)
-#else
int mcdx_init(void)
-#endif
{
int drive;
- WARN(("Version 1.3 "
- "mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp\n"));
- INFO((": Version 1.3 "
- "mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp\n"));
+ WARN(("Version 1.5 "
+ "mcdx.c,v 1.19 1995/11/20 17:06:25 heiko Exp\n"));
+ INFO((": Version 1.5 "
+ "mcdx.c,v 1.19 1995/11/20 17:06:25 heiko Exp\n"));
/* zero the pointer array */
for (drive = 0; drive < MCDX_NDRIVES; drive++)
TRACE((INIT, "init() try drive %d\n", drive));
-#if defined(MODULE) || LINUX_VERSION_CODE > 66338
TRACE((INIT, "kmalloc space for stuffpt's\n"));
TRACE((MALLOC, "init() malloc %d bytes\n", size));
if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
WARN(("init() malloc failed\n"));
break;
}
-#else
- TRACE((INIT, "adjust mem_start\n"));
- stuffp = (struct s_drive_stuff *) mem_start;
- mem_start += size;
-#endif
TRACE((INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp));
TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp));
}
-#if MODULE || LINUX_VERSION_CODE > 66338
return 0;
-#else
- return mem_start;
-#endif
}
* Not for Sanyo drives (but sjcd is there...).
* Not for any other Funai drives than E2550UA (="CD200" with "F").
*
- * NOTE: This is release 3.9.
+ * NOTE: This is release 4.0
+ *
+ * Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg <emoenke@gwdg.de>
+ *
+ * If you change this software, you should mail a .diff
+ * file with some description lines to emoenke@gwdg.de.
+ * I want to know about it.
+ *
+ * If you are the editor of a Linux CD, you should
+ * enable sbpcd.c within your boot floppy kernel and
+ * send me one of your CDs for free.
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* VERSION HISTORY
*
* Now Corey, Heiko, Ken, Leo, Vadim/Eric & Werner are invited to copy
* the config_spea() routine into their drivers. ;-)
*
+ * 4.0 No "big step" - normal version increment.
+ * Adapted the benefits from 1.3.33.
+ * Fiddled with CDROMREADAUDIO flaws.
+ * Avoid ReadCapacity command with CD200 drives (the MKE 1.01 version
+ * seems not to support it).
+ * Fulfilled "read audio" for CD200 drives, with help of Pete Heist
+ * (heistp@rpi.edu).
*
* TODO
*
* the "push" towards load-free wait loops, and for the extensive mail
* thread which brought additional hints and bug fixes.
*
- * Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg <emoenke@gwdg.de>
- *
- * If you change this software, you should mail a .diff
- * file with some description lines to emoenke@gwdg.de.
- * I want to know about it.
- *
- * If you are the editor of a Linux CD, you should
- * enable sbpcd.c within your boot floppy kernel and
- * send me one of your CDs for free.
- *
- * 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, or (at your option)
- * any later version.
- *
- * You should have received a copy of the GNU General Public License
- * (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#ifndef SBPCD_ISSUE
#include <linux/blk.h>
-#define VERSION "v3.9 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "v4.0 Eberhard Moenkeberg <emoenke@gwdg.de>"
/*==========================================================================*/
/*
static int sbpcd_debug = ((1<<DBG_INF) |
(1<<DBG_TOC) |
(1<<DBG_MUL) |
+ (1<<DBG_AUD) |
(1<<DBG_UPC));
#endif DISTRIBUTION
#define SBP_BUFFER_FRAMES 8 /* driver's own read_ahead, data mode */
/*==========================================================================*/
-static u_char family0[]="MATSHITA"; /* MKE CR-52x */
-static u_char family1[]="CR-56"; /* MKE CR-56x */
-static u_char family2[]="CD200"; /* MKE CD200 */
+static u_char family0[]="MATSHITA"; /* MKE CR-521, CR-522, CR-523 */
+static u_char family1[]="CR-56"; /* MKE CR-562, CR-563 */
+static u_char family2[]="CD200"; /* MKE CD200, Funai CD200F */
static u_char familyL[]="LCS-7260"; /* Longshine LCS-7260 */
static u_char familyT[]="CD-55"; /* TEAC CD-55A */
*/
static void sbp_sleep(u_int time)
{
-#ifndef MODULE
- if (current == task[0])
- {
- del_timer(&delay_timer);
- delay_timer.expires=jiffies+time;
- timed_out_delay=0;
- add_timer(&delay_timer);
- while (!timed_out_delay) ;
- return;
- }
-#endif MODULE
sti();
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + time;
{
int i;
-#ifdef MODULE
sbp_sleep(15*HZ/10);
for (i=maxtim_data;i!=0;i--) inb(CDi_status);
-#else
- if (current == task[0])
- for (i=maxtim02;i!=0;i--) inb(CDi_status);
- else
- {
- sbp_sleep(15*HZ/10);
- for (i=maxtim_data;i!=0;i--) inb(CDi_status);
- }
-#endif MODULE
}
/*==========================================================================*/
static int CDi_stat_loop(void)
{
int i,j;
-#ifdef MODULE
for(timeout = jiffies + 10*HZ, i=maxtim_data; timeout > jiffies; )
{
for ( ;i!=0;i--)
sbp_sleep(1);
i = 1;
}
-#else
- if (current == task[0])
- for(i=maxtim16;i!=0;i--)
- {
- j=inb(CDi_status);
- if (!(j&s_not_data_ready)) return (j);
- if (!(j&s_not_result_ready)) return (j);
- if (fam0L_drive) if (j&s_attention) return (j);
- }
- else
- for(timeout = jiffies + 10*HZ, i=maxtim_data; timeout > jiffies; )
- {
- for ( ;i!=0;i--)
- {
- j=inb(CDi_status);
- if (!(j&s_not_data_ready)) return (j);
- if (!(j&s_not_result_ready)) return (j);
- if (fam0L_drive) if (j&s_attention) return (j);
- }
- sbp_sleep(1);
- i = 1;
- }
-#endif MODULE
msg(DBG_LCS,"CDi_stat_loop failed\n");
return (-1);
}
int i,j,st=0;
u_long timeout;
-#ifdef MODULE
- if (0)
-#else
- if (current == task[0])
-#endif MODULE
- for (i=0;i<response_count;i++)
+ for (i=0,timeout=jiffies+HZ;i<response_count;i++)
+ {
+ for (j=maxtim_data; ; )
{
- for (j=maxtim_8;j!=0;j--)
+ for ( ;j!=0;j-- )
{
st=inb(CDi_status);
if (!(st&s_not_result_ready)) break;
}
- if (j==0)
- {
- msg(DBG_SEQ,"ResponseInfo: not_result_ready (got %d of %d bytes).\n", i, response_count);
- break;
- }
- infobuf[i]=inb(CDi_info);
- }
- else
- {
- for (i=0,timeout=jiffies+HZ;i<response_count;i++)
- {
- for (j=maxtim_data; ; )
- {
- for ( ;j!=0;j-- )
- {
- st=inb(CDi_status);
- if (!(st&s_not_result_ready)) break;
- }
- if ((j!=0)||(timeout<=jiffies)) break;
- sbp_sleep(1);
- j = 1;
- }
- if (timeout<=jiffies) break;
- infobuf[i]=inb(CDi_info);
+ if ((j!=0)||(timeout<=jiffies)) break;
+ sbp_sleep(1);
+ j = 1;
}
+ if (timeout<=jiffies) break;
+ infobuf[i]=inb(CDi_info);
}
#if 000
while (!(inb(CDi_status)&s_not_result_ready))
msg(DBG_STA,"doing ResponseStatus...\n");
if (famT_drive) return (get_state_T());
-#ifdef MODULE
- if (0)
-#else
- if (current == task[0])
-#endif MODULE
+ if (flags_cmd_out & f_respo3) timeout = jiffies;
+ else if (flags_cmd_out & f_respo2) timeout = jiffies + 16*HZ;
+ else timeout = jiffies + 4*HZ;
+ j=maxtim_8;
+ do
{
- if (flags_cmd_out & f_respo3) j = maxtim_8;
- else if (flags_cmd_out&f_respo2) j=maxtim16;
- else j=maxtim04;
- for (;j!=0;j--)
- {
+ for ( ;j!=0;j--)
+ {
i=inb(CDi_status);
if (!(i&s_not_result_ready)) break;
}
+ if ((j!=0)||(timeout<jiffies)) break;
+ sbp_sleep(1);
+ j = 1;
}
- else
- {
- if (flags_cmd_out & f_respo3) timeout = jiffies;
- else if (flags_cmd_out & f_respo2) timeout = jiffies + 16*HZ;
- else timeout = jiffies + 4*HZ;
- j=maxtim_8;
- do
- {
- for ( ;j!=0;j--)
- {
- i=inb(CDi_status);
- if (!(i&s_not_result_ready)) break;
- }
- if ((j!=0)||(timeout<jiffies)) break;
- sbp_sleep(1);
- j = 1;
- }
- while (1);
- }
+ while (1);
if (j==0)
{
if ((flags_cmd_out & f_respo3) == 0)
i=inb(CDi_info);
msg(DBG_STA,"ResponseStatus: response %02X.\n", i);
EvaluateStatus(i);
-#if 0
- if (fam0_drive)
-#endif
- msg(DBG_STA,"status_bits=%02X, i=%02X\n",D_S[d].status_bits,i);
-#if 1
+ msg(DBG_STA,"status_bits=%02X, i=%02X\n",D_S[d].status_bits,i);
return (D_S[d].status_bits);
-#else
- return (i);
-#endif 0
}
/*==========================================================================*/
static void cc_ReadStatus(void)
{
int i, j;
+ if (fam2_drive) return (0); /* some firmware lacks this command */
if (famL_drive) return (0); /* some firmware lacks this command */
if (famT_drive) return (0); /* done with cc_ReadTocDescr() */
D_S[d].diskstate_flags &= ~cd_size_bit;
response_count=5;
flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
}
+#if 00
else if (fam2_drive)
{
drvcmd[0]=CMD2_CAPACITY;
response_count=8;
flags_cmd_out=f_putcmd;
}
+#endif
else if (fam0_drive)
{
drvcmd[0]=CMD0_CAPACITY;
if (j==0) return (i);
if (fam1_drive) D_S[d].CDsize_frm=msf2blk(make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])))+CD_MSF_OFFSET;
else if (fam0_drive) D_S[d].CDsize_frm=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2]));
+#if 00
else if (fam2_drive) D_S[d].CDsize_frm=make32(make16(infobuf[0],infobuf[1]),make16(infobuf[2],infobuf[3]));
+#endif
D_S[d].diskstate_flags |= cd_size_bit;
msg(DBG_000,"cc_ReadCapacity: %d frames.\n", D_S[d].CDsize_frm);
return (0);
if (i<0) return (i);
D_S[d].size_msf=make32(make16(0,infobuf[2]),make16(infobuf[3],infobuf[4]));
D_S[d].size_blk=msf2blk(D_S[d].size_msf);
+ D_S[d].CDsize_frm=D_S[d].size_blk+1;
}
else if (famT_drive)
{
response_count=9;
flags_cmd_out=f_putcmd;
i=cmd_out();
- if (i<0) msg(DBG_INI,"CMD0_READERR returns %d (ok anyway).\n",i);
+ if (i<0) msg(DBG_INI,"CMD0_READ_ERR returns %d (ok anyway).\n",i);
/* read drive version */
clr_cmdbuf();
for (i=0;i<12;i++) infobuf[i]=0;
}
else if (fam2_drive)
{
- msg(DBG_INF,"new drive CD200 (%s)detected.\n", D_S[d].firmware_version);
- msg(DBG_INF,"CD200 is not fully supported yet - CD200F should work.\n");
- if ((j!=1)&&(j!=101)&&(j!=35)) ask_mail(); /* unknown version at time */
+ if (D_S[d].drive_model[5]=='F')
+ {
+ if ((j!=1)&&(j!=35)&&(j!=200)&&(j!=210)) ask_mail(); /* unknown version at time */
+ }
+ else
+ {
+ msg(DBG_INF,"this CD200 drive is not fully supported yet - only audio will work.\n");
+ if ((j!=101)&&(j!=35)) ask_mail(); /* unknown version at time */
+ }
}
}
msg(DBG_LCS,"drive type %02X\n",D_S[d].drv_type);
case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */
msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n");
-#ifdef MODULE
- if (D_S[d].sbp_audsiz>0)
- vfree(D_S[d].aud_buf);
-#endif MODULE
+ if (D_S[d].sbp_audsiz>0) vfree(D_S[d].aud_buf);
D_S[d].aud_buf=NULL;
D_S[d].sbp_audsiz=arg;
if (D_S[d].sbp_audsiz>0)
msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n");
if (fam0_drive) return (-EINVAL);
if (famL_drive) return (-EINVAL);
- if (fam2_drive) return (-EINVAL);
if (famT_drive) return (-EINVAL);
if (D_S[d].aud_buf==NULL) return (-EINVAL);
i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio));
else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */
block=read_audio.addr.lba;
else return (-EINVAL);
+#if 000
i=cc_SetSpeed(speed_150,0,0);
if (i) msg(DBG_AUD,"read_audio: SetSpeed error %d\n", i);
+#endif
msg(DBG_AUD,"read_audio: lba: %d, msf: %06X\n",
block, blk2msf(block));
msg(DBG_AUD,"read_audio: before cc_ReadStatus.\n");
flags_cmd_out |= f_respo3;
cc_ReadStatus();
if (sbp_status() != 0) break;
+ if (st_check) cc_ReadError();
sbp_sleep(1); /* wait a bit, try again */
}
if (status_tries == 0)
drvcmd[5]=0;
drvcmd[6]=read_audio.nframes; /* # of frames */
}
- else if (fam2_drive) /* CD200: not tested yet */
+ else if (fam2_drive)
{
+ drvcmd[0]=CMD2_READ_XA2;
+ lba2msf(block,&drvcmd[1]); /* msf-bin format required */
+ drvcmd[4]=0;
+ drvcmd[5]=read_audio.nframes; /* # of frames */
+ drvcmd[6]=0x11; /* raw mode */
}
else if (famT_drive) /* CD-55A: not tested yet */
{
}
/*==========================================================================*/
/*
- * Test for presence of drive and initialize it. Called at boot time.
+ * Test for presence of drive and initialize it.
+ * Called once at boot or load time.
*/
#ifdef MODULE
int init_module(void)
D_S[d].sbp_current = 0; /* Frame being currently read */
D_S[d].CD_changed=1;
D_S[d].frame_size=CD_FRAMESIZE;
+ D_S[d].f_eject=0;
#if EJECT
if (!fam0_drive) D_S[d].f_eject=1;
- else D_S[d].f_eject=0;
-#else
- D_S[d].f_eject=0;
-#endif
-
+#endif EJECT
cc_ReadStatus();
i=ResponseStatus(); /* returns orig. status or p_busy_new */
if (famT_drive) i=ResponseStatus(); /* returns orig. status or p_busy_new */
msg(DBG_INF,"data buffer (%d frames) not available.\n",D_S[j].sbp_bufsiz);
return -EIO;
}
+#ifdef MODULE
msg(DBG_INF,"data buffer size: %d frames.\n",SBP_BUFFER_FRAMES);
+#endif MODULE
if (D_S[j].sbp_audsiz>0)
{
D_S[j].aud_buf=(u_char *) vmalloc(D_S[j].sbp_audsiz*CD_FRAMESIZE_RAW);
}
blksize_size[MAJOR_NR]=sbpcd_blocksizes;
-#ifdef MODULE
- return (0);
-#else
init_done:
+#ifndef MODULE
#if !(SBPCD_ISSUE-1)
#ifdef CONFIG_SBPCD2
sbpcd2_init();
-#endif
+#endif CONFIG_SBPCD2
#ifdef CONFIG_SBPCD3
sbpcd3_init();
-#endif
+#endif CONFIG_SBPCD3
#ifdef CONFIG_SBPCD4
sbpcd4_init();
-#endif
-#endif
- return 0;
+#endif CONFIG_SBPCD4
+#endif !(SBPCD_ISSUE-1)
#endif MODULE
+ return 0;
}
/*==========================================================================*/
#ifdef MODULE
{
if (D_S[j].drv_id==-1) continue;
vfree(D_S[j].sbp_buf);
- if (D_S[j].sbp_audsiz>0)
- vfree(D_S[j].aud_buf);
+ if (D_S[j].sbp_audsiz>0) vfree(D_S[j].aud_buf);
}
msg(DBG_INF, "%s module released.\n", major_name);
}
* added fasync support
*
* Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
+ *
+ * Replaced dumb busy loop with udelay() 16 Nov 95
+ * Nathan Laredo <laredo@gnu.ai.mit.edu>
+ *
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/mouse.h>
#include <linux/random.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/segment.h>
outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
- for (i = 0; i < 100000; i++)
- /* busy loop */;
+ udelay(100L); /* wait for reply from mouse */
if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
mouse.present = 0;
return -EIO;
* Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
* <poe@daimi.aau.dk>
*
+ * User-defined bell sound, new setterm control sequences and printk
+ * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
+ *
*/
#define BLANK 0x0020
extern void compute_shiftstate(void);
extern void reset_palette(int currcons);
extern void set_palette(void);
-extern unsigned long con_type_init(unsigned long, char *);
+extern unsigned long con_type_init(unsigned long, const char **);
extern int set_get_cmap(unsigned char *, int);
extern int set_get_font(unsigned char *, int, int);
blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
poke_blanked_console();
break;
+ case 10: /* set bell frequency in Hz */
+ if (npar >= 1)
+ bell_pitch = (par[1] < 20 || par[1] > 32767) ?
+ 0 : 1193180 / par[1];
+ else
+ bell_pitch = 0x637;
+ break;
+ case 11: /* set bell duration in msec */
+ if (npar >= 1)
+ bell_duration = (par[1] < 2000) ?
+ par[1]*HZ/1000 : 0;
+ else
+ bell_duration = HZ/8;
+ break;
+ case 12: /* bring specified console to the front */
+ if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
+ update_screen(par[1]-1);
+ break;
+ case 13: /* unblank the screen */
+ unblank_screen();
+ break;
}
}
tab_stop[3] =
tab_stop[4] = 0x01010101;
+ bell_pitch = 0x637;
+ bell_duration = HZ/8;
+
gotoxy(currcons,0,0);
save_cur(currcons);
if (do_clear)
*/
switch (c) {
case 7:
- kd_mksound(0x637, HZ/8);
+ if (bell_pitch && bell_duration)
+ kd_mksound(bell_pitch, bell_duration);
continue;
case 8:
bs(currcons);
return; /* console not yet initialized */
printing = 1;
+ if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
+ currcons = kmsg_redirect - 1;
+
if (!vc_cons_allocated(currcons)) {
/* impossible */
printk("console_print: tty %d not allocated ??\n", currcons+1);
*/
unsigned long con_init(unsigned long kmem_start)
{
- char display_desc[] = "????";
+ const char *display_desc = "????";
int currcons = 0;
int orig_x = ORIG_X;
int orig_y = ORIG_Y;
timer_active |= 1<<BLANK_TIMER;
}
- kmem_start = con_type_init(kmem_start, display_desc);
+ kmem_start = con_type_init(kmem_start, &display_desc);
/* Initialize the variables used for scrolling (mostly EGA/VGA) */
unsigned char vc_G1_charset;
unsigned char vc_saved_G0;
unsigned char vc_saved_G1;
+ unsigned int vc_bell_pitch; /* Console bell pitch */
+ unsigned int vc_bell_duration; /* Console bell duration */
/* additional information is in vt_kern.h */
};
#define halfcolor (vc_cons[currcons].d->vc_halfcolor)
#define tab_stop (vc_cons[currcons].d->vc_tab_stop)
#define palette (vc_cons[currcons].d->vc_palette)
+#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch)
+#define bell_duration (vc_cons[currcons].d->vc_bell_duration)
#define vcmode (vt_cons[currcons]->vc_mode)
#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct))
}
unsigned long
-con_type_init(unsigned long kmem_start, char *display_desc)
+con_type_init(unsigned long kmem_start, const char **display_desc)
{
can_do_color = 1;
video_type = VIDEO_TYPE_TGAC;
- strcpy(display_desc,"TGA");
+ *display_desc = "TGA";
return kmem_start;
}
for ( j = 0; j < TGA_F_HEIGHT_PADDED; j++ ) {
if (j < TGA_F_HEIGHT) {
- rowbits = *font_row++;
- data = fontmask_bits[(rowbits>>4)&0xf];
- data = (data & fgmask) | (~data & bgmask);
- writel(data, dst);
- data = fontmask_bits[rowbits&0xf];
- data = (data & fgmask) | (~data & bgmask);
- writel(data, (dst+1));
+ rowbits = font_row[j];
} else {
- writel(bgmask, dst);
- writel(bgmask, (dst+1));
+ /* dup the last n rows only if char > 0x7f */
+ if (c & 0x80)
+ rowbits = font_row[j-(TGA_F_HEIGHT_PADDED-TGA_F_HEIGHT)];
+ else
+ rowbits = 0;
}
+ data = fontmask_bits[(rowbits>>4)&0xf];
+ data = (data & fgmask) | (~data & bgmask);
+ writel(data, dst);
+ data = fontmask_bits[rowbits&0xf];
+ data = (data & fgmask) | (~data & bgmask);
+ writel(data, (dst+1));
dst += stride;
}
} else { /* 24-plane */
for ( i = 0; i < TGA_F_HEIGHT_PADDED; i++ ) {
if (i < TGA_F_HEIGHT) {
- rowbits = *font_row++;
- data = 1 << (TGA_F_WIDTH - 1);
- for (j = 0; j < TGA_F_WIDTH; j++, data >>= 1) {
- if (rowbits & data)
- writel(fgmask, (dst+j));
- else
- writel(bgmask, (dst+j));
- }
+ rowbits = font_row[i];
} else {
- for (j = 0; j < TGA_F_WIDTH; j++) {
+ /* dup the last n rows only if char > 0x7f */
+ if (c & 0x80)
+ rowbits = font_row[i-(TGA_F_HEIGHT_PADDED-TGA_F_HEIGHT)];
+ else
+ rowbits = 0;
+ }
+ data = 1 << (TGA_F_WIDTH - 1);
+ for (j = 0; j < TGA_F_WIDTH; j++, data >>= 1) {
+ if (rowbits & data)
+ writel(fgmask, (dst+j));
+ else
writel(bgmask, (dst+j));
- }
}
dst += stride;
}
#include <asm/io.h>
#include <asm/segment.h>
+/* We really shouldn't be using this define.. */
+#define IOCCMD_MASK 0x0000ffff
+
/* check existence of required configuration parameters */
#if !defined(QIC02_CMD_PORT) || \
!defined(QIC02_TAPE_IRQ) || \
*
* Reorganized FASYNC support so mouse code can share it.
* -- ctm@ardi.com, 9Sep95
+ *
+ * New TIOCLINUX variants added.
+ * -- mj@k332.feld.cvut.cz, 19-Nov-95
*/
#include <linux/config.h>
/*
* fg_console is the current virtual console,
- * last_console is the last used one
+ * last_console is the last used one,
+ * kmsg_redirect is the console for kernel messages,
* redirect is the pseudo-tty that console output
* is redirected to if asked by TIOCCONS.
*/
int fg_console = 0;
int last_console = 0;
+int kmsg_redirect = 0;
struct tty_struct * redirect = NULL;
struct wait_queue * keypress_wait = NULL;
case 10:
set_vesa_blanking(arg);
return 0;
+ case 11: /* set kmsg redirect */
+ if (!suser())
+ return -EPERM;
+ retval = verify_area(VERIFY_READ,
+ (void *) arg+1, 1);
+ if (retval)
+ return retval;
+ kmsg_redirect = get_user((char *)arg+1);
+ return 0;
+ case 12: /* get fg_console */
+ return fg_console;
default:
return -EINVAL;
}
}
unsigned long
-con_type_init(unsigned long kmem_start, char *display_desc)
+con_type_init(unsigned long kmem_start, const char **display_desc)
{
if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
{
{
video_type = VIDEO_TYPE_EGAM;
video_mem_term = 0xb8000;
- strcpy(display_desc, "EGA+");
+ *display_desc = "EGA+";
request_region(0x3b0,16,"ega");
}
else
{
video_type = VIDEO_TYPE_MDA;
video_mem_term = 0xb2000;
- strcpy(display_desc, "*MDA");
+ *display_desc = "*MDA";
request_region(0x3b0,12,"mda");
request_region(0x3bf, 1,"mda");
}
if (!ORIG_VIDEO_ISVGA) {
video_type = VIDEO_TYPE_EGAC;
- strcpy(display_desc, "EGA");
+ *display_desc = "EGA";
request_region(0x3c0,32,"ega");
} else {
video_type = VIDEO_TYPE_VGAC;
- strcpy(display_desc, "VGA+");
+ *display_desc = "VGA+";
request_region(0x3c0,32,"vga+");
#ifdef VGA_CAN_DO_64KB
{
video_type = VIDEO_TYPE_CGA;
video_mem_term = 0xba000;
- strcpy(display_desc, "*CGA");
+ *display_desc = "*CGA";
request_region(0x3d4,2,"cga");
}
}
if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
(status_byte(SCpnt->result) & CHECK_CONDITION)) &&
((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
- if (SCpnt->sense_buffer[2] &0xe0)
- continue; /* No devices here... */
if(((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION))
continue;
timer_table[SCSI_TIMER].expires = 0;
- /* Register the core /proc/scsi entry */
+ /* Register the /proc/scsi/scsi entry */
#if CONFIG_PROC_FS
proc_scsi_register(0, &proc_scsi_scsi);
#endif
timer_table[SCSI_TIMER].expires = 0;
register_symtab(&scsi_symbol_table);
scsi_loadable_module_flag = 1;
+
+ /* Register the /proc/scsi/scsi entry */
+#if CONFIG_PROC_FS
+ proc_scsi_register(0, &proc_scsi_scsi);
+#endif
+
dma_sectors = PAGE_SIZE / 512;
dma_free_sectors= dma_sectors;
void cleanup_module( void)
{
- if (MOD_IN_USE) {
- printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
- return;
- }
-
+#if CONFIG_PROC_FS
+ proc_scsi_unregister(0, PROC_SCSI_SCSI);
+#endif
+
/* No, we're not here anymore. Don't show the /proc/scsi files. */
dispatch_scsi_info_ptr = 0L;
* transfer rate if handshaking isn't working correctly.
*/
-#ifdef MODULE
#include <linux/module.h>
-#endif
#include <asm/io.h>
#include <asm/system.h>
static int sg_detect(Scsi_Device * SDp){
- ++sg_template.dev_noticed;
+
+ switch (SDp->type) {
+ case TYPE_DISK:
+ case TYPE_MOD:
+ case TYPE_ROM:
+ case TYPE_WORM:
+ case TYPE_TAPE: break;
+ default:
+ printk("Detected scsi generic sg%c at scsi%d, channel %d, id %d, lun %d\n",
+ 'a'+sg_template.dev_noticed,
+ SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+ }
+ sg_template.dev_noticed++;
return 1;
}
mpnt->vm_start = PAGE_MASK & (unsigned long) p;
mpnt->vm_end = TASK_SIZE;
mpnt->vm_page_prot = PAGE_COPY;
-#ifdef VM_STACK_FLAGS
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_pte = 0;
-#else
-# ifdef VM_GROWSDOWN
- mpnt->vm_flags = VM_GROWSDOWN;
-# endif
-#endif
mpnt->vm_inode = NULL;
mpnt->vm_offset = 0;
mpnt->vm_ops = NULL;
insert_vm_struct(current, mpnt);
-#ifndef VM_GROWSDOWN
- current->mm->stk_vma = mpnt;
-#endif
-
+ current->mm->total_vm += (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
}
sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
sp -= exec ? DLINFO_ITEMS*2 : 2;
k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
if(k > elf_bss) elf_bss = k;
- SYS(close)(fd);
if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
kfree(elf_phdata);
return error;
mpnt->vm_inode = NULL;
mpnt->vm_pte = 0;
insert_vm_struct(current, mpnt);
+ current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
}
sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
#ifdef __alpha__
return;
}
*mm = *current->mm;
+ mm->def_flags = 0; /* should future lockings be kept? */
mm->count = 1;
mm->mmap = NULL;
mm->mmap_avl = NULL;
+ mm->total_vm = 0;
+ mm->rss = 0;
current->mm->count--;
current->mm = mm;
new_page_tables(current);
unsigned long error;
unsigned long p = bprm->p;
unsigned long fd_offset;
+ unsigned long rlim;
ex = *((struct exec *) bprm->buf); /* exec-header */
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
}
#endif
+ /* Check initial limits. This avoids letting people circumvent
+ * size limits imposed on them by creating programs with large
+ * arrays in the data or bss.
+ */
+ rlim = current->rlim[RLIMIT_DATA].rlim_cur;
+ if (rlim >= RLIM_INFINITY)
+ rlim = ~0;
+ if (ex.a_data + ex.a_bss > rlim)
+ return -ENOMEM;
+
/* OK, This is the point of no return */
flush_old_exec(bprm);
device_setup();
-#ifdef CONFIG_MINIX_FS
- register_filesystem(&(struct file_system_type)
- {minix_read_super, "minix", 1, NULL});
-#endif
-
#ifdef CONFIG_EXT_FS
register_filesystem(&(struct file_system_type)
{ext_read_super, "ext", 1, NULL});
register_filesystem(&(struct file_system_type)
{xiafs_read_super, "xiafs", 1, NULL});
#endif
+
+#ifdef CONFIG_MINIX_FS
+ register_filesystem(&(struct file_system_type)
+ {minix_read_super, "minix", 1, NULL});
+#endif
+
#ifdef CONFIG_UMSDOS_FS
register_filesystem(&(struct file_system_type)
{UMSDOS_read_super, "umsdos", 1, NULL});
{ NULL, 0, 0 }};
-unsigned long get_address (char **str)
+static unsigned long get_address (char **str)
{
unsigned long l;
unsigned int val;
sin=(struct sockaddr_in *)&server_route.rt_genmask;
sin->sin_family=AF_INET;
sin->sin_addr.s_addr= root_dev->pa_mask;
- server_route.rt_dev[0]=0;
+ server_route.rt_dev=NULL;
server_route.rt_flags=RTF_HOST|RTF_UP;
/* Now add a route to the server */
len = sprintf(buffer,
"cpu %u %u %u %lu\n"
"disk %u %u %u %u\n"
+ "disk_rio %u %u %u %u\n"
+ "disk_wio %u %u %u %u\n"
+ "disk_rblk %u %u %u %u\n"
+ "disk_wblk %u %u %u %u\n"
"page %u %u\n"
"swap %u %u\n"
"intr %u",
kstat.cpu_nice,
kstat.cpu_system,
jiffies - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
- kstat.dk_drive[0],
- kstat.dk_drive[1],
- kstat.dk_drive[2],
- kstat.dk_drive[3],
+ kstat.dk_drive[0], kstat.dk_drive[1],
+ kstat.dk_drive[2], kstat.dk_drive[3],
+ kstat.dk_drive_rio[0], kstat.dk_drive_rio[1],
+ kstat.dk_drive_rio[2], kstat.dk_drive_rio[3],
+ kstat.dk_drive_wio[0], kstat.dk_drive_wio[1],
+ kstat.dk_drive_wio[2], kstat.dk_drive_wio[3],
+ kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1],
+ kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3],
+ kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1],
+ kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3],
kstat.pgpgin,
kstat.pgpgout,
kstat.pswpin,
#define MAP_GROWSDOWN 0x1000 /* stack-like segment */
#define MAP_DENYWRITE 0x2000 /* ETXTBSY */
#define MAP_EXECUTABLE 0x4000 /* mark it as a executable */
+#define MAP_LOCKED 0x8000 /* lock the mapping */
#define MS_ASYNC 1 /* sync memory asynchronously */
#define MS_SYNC 2 /* synchronous memory sync */
#define MS_INVALIDATE 4 /* invalidate the caches */
+#define MCL_CURRENT 8192 /* lock all currently mapped pages */
+#define MCL_FUTURE 16384 /* lock all additions to address space */
+
#endif /* __ALPHA_MMAN_H__ */
#define PAGE_OFFSET 0xFFFFFC0000000000
#define MAP_NR(addr) ((((unsigned long) (addr)) - PAGE_OFFSET) >> PAGE_SHIFT)
-typedef struct {
- unsigned count:24,
- age:6,
- dirty:1,
- reserved:1;
-} mem_map_t;
-
-
#endif /* __KERNEL__ */
#endif /* _ALPHA_PAGE_H */
#define RLIMIT_NOFILE 6 /* max number of open files */
#define RLIMIT_AS 7 /* address space limit(?) */
#define RLIMIT_NPROC 8 /* max number of processes */
+#define RLIMIT_MEMLOCK 9 /* max locked-in-memory address space */
-#ifdef notdef
-#define RLIMIT_MEMLOCK 9 /* max locked-in-memory address space*/
-#endif
-
-#define RLIM_NLIMITS 9
+#define RLIM_NLIMITS 10
#ifdef __KERNEL__
{ NR_OPEN, NR_OPEN}, /* RLIMIT_NOFILE */ \
{LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \
{MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, /* RLIMIT_NPROC */ \
+ {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \
}
#endif /* __KERNEL__ */
#define MAP_GROWSDOWN 0x0100 /* stack-like segment */
#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
#define MAP_EXECUTABLE 0x1000 /* mark it as a executable */
+#define MAP_LOCKED 0x2000 /* pages are locked */
#define MS_ASYNC 1 /* sync memory asynchronously */
#define MS_INVALIDATE 2 /* invalidate the caches */
#define MS_SYNC 4 /* synchronous memory sync */
+#define MCL_CURRENT 1 /* lock all current mappings */
+#define MCL_FUTURE 2 /* lock all future mappings */
+
#endif /* __I386_MMAN_H__ */
#define PAGE_OFFSET 0
#define MAP_NR(addr) (((unsigned long)(addr)) >> PAGE_SHIFT)
-typedef struct {
- unsigned count:24,
- age:6,
- dirty:1,
- reserved:1;
-} mem_map_t;
-
#endif /* __KERNEL__ */
#endif /* _I386_PAGE_H */
#define RLIMIT_RSS 5 /* max resident set size */
#define RLIMIT_NPROC 6 /* max number of processes */
#define RLIMIT_NOFILE 7 /* max number of open files */
+#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */
-#ifdef notdef
-#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space*/
-#endif
-
-#define RLIM_NLIMITS 8
+#define RLIM_NLIMITS 9
#ifdef __KERNEL__
-#define INIT_RLIMITS \
-{ \
- {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \
- {LONG_MAX, LONG_MAX}, {_STK_LIM, _STK_LIM}, \
- { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \
- {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, {NR_OPEN, NR_OPEN} \
+#define INIT_RLIMITS \
+{ \
+ { LONG_MAX, LONG_MAX }, \
+ { LONG_MAX, LONG_MAX }, \
+ { LONG_MAX, LONG_MAX }, \
+ { _STK_LIM, _STK_LIM }, \
+ { 0, LONG_MAX }, \
+ { LONG_MAX, LONG_MAX }, \
+ { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER }, \
+ { NR_OPEN, NR_OPEN }, \
+ { LONG_MAX, LONG_MAX }, \
}
#endif /* __KERNEL__ */
#define __NR_readv 145
#define __NR_writev 146
+#define __NR_mlock 150
+#define __NR_munlock 151
+#define __NR_mlockall 152
+#define __NR_munlockall 153
+
/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
#define _syscall0(type,name) \
type name(void) \
#define _LINUX_BUSMOUSE_H
/*
- * linux/include/linux/mouse.h: header file for Logitech Bus Mouse driver
+ * linux/include/linux/busmouse.h: header file for Logitech Bus Mouse driver
* by James Banks
*
* based on information gleamed from various mouse drivers on the net
#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */
#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */
#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */
-#define CD_XA_SYNC_HEAD (CD_XA_HEAD+12)/* sync bytes + header of XA frame */
+#define CD_XA_SYNC_HEAD (CD_SYNC_SIZE+CD_XA_HEAD)/* sync bytes + header of XA frame */
#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */
#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */
#define CDROMSUBCHNL 0x530b /* (struct cdrom_subchnl) */
#define CDROMREADMODE2 0x530c /* (struct cdrom_read) */
- /* read type-2 data (not suppt) */
+ /* read type-2 data */
#define CDROMREADMODE1 0x530d /* (struct cdrom_read) */
/* read type-1 data */
*/
#define CDROMREADRAW 0x5314 /* read data in raw mode */
#define CDROMREADCOOKED 0x5315 /* read data in cooked mode */
-#define CDROMSEEK 0x5316 /*seek msf address*/
+#define CDROMSEEK 0x5316 /* seek msf address */
/*
* for playing audio in logical block addressing mode
*/
#define CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */
+
/*
* CD-ROM-specific SCSI command opcodes
*/
/* Now define a bunch of things for manipulating the control register.
The top two bytes of the control register consist of 4 fields of 4
- bytes - each field corresponds to one of the four debug registers,
+ bits - each field corresponds to one of the four debug registers,
and indicates what types of access we trap on, and how large the data
field is that we are looking at */
struct kernel_stat {
unsigned int cpu_user, cpu_nice, cpu_system;
unsigned int dk_drive[DK_NDRIVE];
+ unsigned int dk_drive_rio[DK_NDRIVE];
+ unsigned int dk_drive_wio[DK_NDRIVE];
+ unsigned int dk_drive_rblk[DK_NDRIVE];
+ unsigned int dk_drive_wblk[DK_NDRIVE];
unsigned int pgpgin, pgpgout;
unsigned int pswpin, pswpout;
unsigned int interrupts[NR_IRQS];
#define MODIFY_LDT_CONTENTS_STACK 1
#define MODIFY_LDT_CONTENTS_CODE 2
-extern int get_ldt(void *buffer);
-extern int set_ldt_entry(int entry, unsigned long base, unsigned int limit,
- int seg_32bit_flag, int contents, int read_only_flag,
- int limit_in_pages_flag);
-
#endif
/*
* Definitions for the Mitsumi CDROM interface
* Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.3
+ * VERSION: 1.5
*
* 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
#define VM_GROWSDOWN 0x0100 /* general info on the segment */
#define VM_GROWSUP 0x0200
-#define VM_SHM 0x0400
+#define VM_SHM 0x0400 /* shared memory area, don't swap out */
#define VM_DENYWRITE 0x0800 /* ETXTBSY on write attempts.. */
#define VM_EXECUTABLE 0x1000
-#define VM_DONTSWAP 0x2000 /* Some vm types have their own
- * hard-coded swap mechanism */
+#define VM_LOCKED 0x2000
#define VM_STACK_FLAGS 0x0177
pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
};
+typedef struct {
+ unsigned count:24,
+ age:6,
+ dirty:1,
+ reserved:1;
+} mem_map_t;
+
extern mem_map_t * mem_map;
-extern unsigned char *age_map;
-
-/* planning stage.. */
-#define P_DIRTY 0x0001
-#define P_LOCKED 0x0002
-#define P_UPTODATE 0x0004
-#define P_RESERVED 0x8000
-
-struct page_info {
- unsigned short flags;
- unsigned short count;
- struct inode * inode;
- unsigned long offset;
- struct page_info * next_same_inode;
- struct page_info * prev_same_inode;
- struct page_info * next_hash;
- struct page_info * prev_hash;
- struct wait_queue *wait;
-};
-/* end of planning stage */
/*
* Free area management
#define avl_empty (struct vm_area_struct *) NULL
+static inline int expand_stack(struct vm_area_struct * vma, unsigned long address)
+{
+ unsigned long grow;
+
+ address &= PAGE_MASK;
+ if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
+ return -ENOMEM;
+ grow = vma->vm_start - address;
+ vma->vm_start = address;
+ vma->vm_offset -= grow;
+ vma->vm_mm->total_vm += grow >> PAGE_SHIFT;
+ if (vma->vm_flags & VM_LOCKED)
+ vma->vm_mm->locked_vm += grow >> PAGE_SHIFT;
+ return 0;
+}
+
/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
static inline struct vm_area_struct * find_vma (struct task_struct * task, unsigned long addr)
{
/* Set this to 0 after you have configured your interface definitions right. */
#define DISTRIBUTION 1
+#if DISTRIBUTION
+#define READ_AUDIO 0
+#else
/* max. number of audio frames to read with one */
/* request (allocates n* 2352 bytes kernel memory!) */
/* may be freely adjusted, f.e. 75 (= 1 sec.), at */
/* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */
-#define READ_AUDIO 0
+#define READ_AUDIO 75
/* tray control: eject tray if no disk is in (0 or 1) */
#define JUKEBOX 1
/* tray control: eject tray after last use (0 or 1) */
#define EJECT 1
+#endif DISTRIBUTION
/*==========================================================================*/
/*==========================================================================*/
#define CMD0_READ_XA 0x03
#define CMD2_READ_XA 0xd4
+#define CMD2_READ_XA2 0xd5
#define CMDL_READ_XA CMD0_READ_XA /* really ?? */
#define CMD0_READ_HEAD 0x04
#define CMD2_STATUS 0x00
#define CMDT_STATUS CMD2_STATUS
#define CMDL_STATUS CMD0_STATUS
+#define CMD2_SEEK_LEADIN 0x00
#define CMD0_READ_ERR 0x82
#define CMD1_READ_ERR CMD0_READ_ERR
#define TASK_STOPPED 4
#define TASK_SWAPPING 5
+/*
+ * Scheduling policies
+ */
+#define SCHED_OTHER 0
+#define SCHED_FIFO 1
+#define SCHED_RR 2
+
#ifndef NULL
#define NULL ((void *) 0)
#endif
unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack, start_mmap;
unsigned long arg_start, arg_end, env_start, env_end;
- unsigned long rss;
+ unsigned long rss, total_vm, locked_vm;
+ unsigned long def_flags;
struct vm_area_struct * mmap;
struct vm_area_struct * mmap_avl;
};
0, 0, 0, 0, \
0, 0, 0, 0, \
0, 0, 0, 0, \
+ 0, 0, 0, \
0, \
&init_mmap, &init_mmap }
struct wait_queue *wait_chldexit; /* for wait4() */
unsigned short uid,euid,suid,fsuid;
unsigned short gid,egid,sgid,fsgid;
- unsigned long timeout;
+ unsigned long timeout, policy;
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;
*/
#define _STK_LIM (8*1024*1024)
-#define DEF_PRIORITY (15*HZ/100) /* 150 ms time slices */
+#define DEF_PRIORITY (20*HZ/100) /* 200 ms time slices */
/*
* INIT_TASK is used to set up the first task table, touch at
/* suppl grps*/ {NOGROUP,}, \
/* proc links*/ &init_task,&init_task,NULL,NULL,NULL,NULL, \
/* uid etc */ 0,0,0,0,0,0,0,0, \
-/* timeout */ 0,0,0,0,0,0,0, \
+/* timeout */ 0,SCHED_OTHER,0,0,0,0,0,0, \
/* timer */ { NULL, NULL, 0, 0, it_real_fn }, \
/* utime */ 0,0,0,0,0, \
/* flt */ 0,0,0,0,0,0, \
unsigned short orig_video_page;
unsigned char orig_video_mode;
unsigned char orig_video_cols;
- unsigned short orig_video_ega_ax;
+ unsigned short unused2;
unsigned short orig_video_ega_bx;
- unsigned short orig_video_ega_cx;
+ unsigned short unused3;
unsigned char orig_video_lines;
unsigned char orig_video_isVGA;
unsigned short orig_video_points;
#define ORIG_VIDEO_PAGE (screen_info.orig_video_page)
#define ORIG_VIDEO_MODE (screen_info.orig_video_mode)
#define ORIG_VIDEO_COLS (screen_info.orig_video_cols)
-#define ORIG_VIDEO_EGA_AX (screen_info.orig_video_ega_ax)
#define ORIG_VIDEO_EGA_BX (screen_info.orig_video_ega_bx)
-#define ORIG_VIDEO_EGA_CX (screen_info.orig_video_ega_cx)
#define ORIG_VIDEO_LINES (screen_info.orig_video_lines)
#define ORIG_VIDEO_ISVGA (screen_info.orig_video_isVGA)
#define ORIG_VIDEO_POINTS (screen_info.orig_video_points)
extern struct tty_struct * redirect;
extern struct tty_ldisc ldiscs[];
extern int fg_console;
+extern int kmsg_redirect;
extern struct wait_queue * keypress_wait;
extern unsigned long con_init(unsigned long);
int ramdisk_size;
int root_mountflags = MS_RDONLY;
+char *execute_command = 0;
#ifdef CONFIG_ROOT_NFS
char nfs_root_name[256] = { 0, };
console_loglevel = 10;
continue;
}
+ if (!strncmp(line,"init=",5)) {
+ line += 5;
+ execute_command = line;
+ continue;
+ }
if (checksetup(line))
continue;
/*
(void) dup(0);
(void) dup(0);
- execve("/etc/init",argv_init,envp_init);
- execve("/bin/init",argv_init,envp_init);
- execve("/sbin/init",argv_init,envp_init);
- /* if this fails, fall through to original stuff */
+ if (!execute_command) {
+ execve("/etc/init",argv_init,envp_init);
+ execve("/bin/init",argv_init,envp_init);
+ execve("/sbin/init",argv_init,envp_init);
+ /* if this fails, fall through to original stuff */
+
+ pid = kernel_thread(do_rc, "/etc/rc", SIGCHLD);
+ if (pid>0)
+ while (pid != wait(&i))
+ /* nothing */;
+ }
- pid = kernel_thread(do_rc, "/etc/rc", SIGCHLD);
- if (pid>0)
- while (pid != wait(&i))
- /* nothing */;
while (1) {
- pid = kernel_thread(do_shell, "/bin/sh", SIGCHLD);
+ pid = kernel_thread(do_shell,
+ execute_command ? execute_command : "/bin/sh",
+ SIGCHLD);
if (pid < 0) {
printf("Fork failed in init\n\r");
continue;
#ifdef CONFIG_BOGUS
#endif
+#define version(a) Version_ ## a
+#define version_string(a) version(a)
+
+int version_string(LINUX_VERSION_CODE) = 0;
+
struct new_utsname system_utsname = {
UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION,
UTS_MACHINE, UTS_DOMAINNAME
do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
/* add new mapping */
+ current->mm->total_vm += (shmd->vm_end - shmd->vm_start) >> PAGE_SHIFT;
insert_vm_struct(current, shmd);
merge_segments(current, shmd->vm_start, shmd->vm_end);
shmd->vm_end = addr + shp->shm_npages * PAGE_SIZE;
shmd->vm_mm = current->mm;
shmd->vm_page_prot = (shmflg & SHM_RDONLY) ? PAGE_READONLY : PAGE_SHARED;
- shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED | VM_DONTSWAP
+ shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED
| VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
| ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE);
shmd->vm_next_share = shmd->vm_prev_share = NULL;
return -ENOMEM;
}
*tmp = *mpnt;
+ tmp->vm_flags &= ~VM_LOCKED;
tmp->vm_mm = mm;
tmp->vm_next = NULL;
if (tmp->vm_inode) {
return -1;
*tsk->mm = *current->mm;
tsk->mm->count = 1;
+ tsk->mm->def_flags = 0;
tsk->min_flt = tsk->maj_flt = 0;
tsk->cmin_flt = tsk->cmaj_flt = 0;
tsk->nswap = tsk->cnswap = 0;
if (p->counter > current->counter + 3)
need_resched = 1;
nr_running++;
- (p->next_run = init_task.next_run)->prev_run = p;
- p->prev_run = &init_task;
- init_task.next_run = p;
+ (p->prev_run = init_task.prev_run)->next_run = p;
+ p->next_run = &init_task;
+ init_task.prev_run = p;
}
static inline void del_from_runqueue(struct task_struct * p)
p->prev_run = NULL;
}
+static inline void move_last_runqueue(struct task_struct * p)
+{
+ struct task_struct *next = p->next_run;
+ struct task_struct *prev = p->prev_run;
+
+ next->prev_run = prev;
+ prev->next_run = next;
+ (p->prev_run = init_task.prev_run)->next_run = p;
+ p->next_run = &init_task;
+ init_task.prev_run = p;
+}
+
/*
* Wake up a process. Put it on the run-queue if it's not
* already there. The "current" process is always on the
return -1000;
#endif
+ /*
+ * Realtime process, select the first one on the
+ * runqueue (taking priorities within processes
+ * into account).
+ */
+ if (p->policy != SCHED_OTHER)
+ return 1000 + p->priority;
+
/*
* Give the process a first-approximation goodness value
* according to the number of clock-ticks it has left.
*/
weight = p->counter;
if (weight) {
-
+
#ifdef __SMP__
/* Give a largish advantage to the same processor... */
/* (this is equivalent to penalizing other processors) */
need_resched = 0;
cli();
+ /* move an exhausted RR process to be last.. */
+ if (!current->counter && current->policy == SCHED_RR) {
+ current->counter = current->priority;
+ move_last_runqueue(current);
+ }
switch (current->state) {
case TASK_INTERRUPTIBLE:
if (current->signal & ~current->blocked)
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := mm.o
-O_OBJS := memory.o swap.o mmap.o filemap.o mprotect.o kmalloc.o vmalloc.o
+O_OBJS := memory.o swap.o mmap.o filemap.o mprotect.o mlock.o \
+ kmalloc.o vmalloc.o
include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * linux/mm/mlock.c
+ *
+ * (C) Copyright 1995 Linus Torvalds
+ */
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <linux/mman.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+
+static inline int mlock_fixup_all(struct vm_area_struct * vma, int newflags)
+{
+ vma->vm_flags = newflags;
+ return 0;
+}
+
+static inline int mlock_fixup_start(struct vm_area_struct * vma,
+ unsigned long end, int newflags)
+{
+ struct vm_area_struct * n;
+
+ n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+ if (!n)
+ return -EAGAIN;
+ *n = *vma;
+ vma->vm_start = end;
+ n->vm_end = end;
+ vma->vm_offset += vma->vm_start - n->vm_start;
+ n->vm_flags = newflags;
+ if (n->vm_inode)
+ n->vm_inode->i_count++;
+ if (n->vm_ops && n->vm_ops->open)
+ n->vm_ops->open(n);
+ insert_vm_struct(current, n);
+ return 0;
+}
+
+static inline int mlock_fixup_end(struct vm_area_struct * vma,
+ unsigned long start, int newflags)
+{
+ struct vm_area_struct * n;
+
+ n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+ if (!n)
+ return -EAGAIN;
+ *n = *vma;
+ vma->vm_end = start;
+ n->vm_start = start;
+ n->vm_offset += n->vm_start - vma->vm_start;
+ n->vm_flags = newflags;
+ if (n->vm_inode)
+ n->vm_inode->i_count++;
+ if (n->vm_ops && n->vm_ops->open)
+ n->vm_ops->open(n);
+ insert_vm_struct(current, n);
+ return 0;
+}
+
+static inline int mlock_fixup_middle(struct vm_area_struct * vma,
+ unsigned long start, unsigned long end, int newflags)
+{
+ struct vm_area_struct * left, * right;
+
+ left = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+ if (!left)
+ return -EAGAIN;
+ right = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+ if (!right) {
+ kfree(left);
+ return -EAGAIN;
+ }
+ *left = *vma;
+ *right = *vma;
+ left->vm_end = start;
+ vma->vm_start = start;
+ vma->vm_end = end;
+ right->vm_start = end;
+ vma->vm_offset += vma->vm_start - left->vm_start;
+ right->vm_offset += right->vm_start - left->vm_start;
+ vma->vm_flags = newflags;
+ if (vma->vm_inode)
+ vma->vm_inode->i_count += 2;
+ if (vma->vm_ops && vma->vm_ops->open) {
+ vma->vm_ops->open(left);
+ vma->vm_ops->open(right);
+ }
+ insert_vm_struct(current, left);
+ insert_vm_struct(current, right);
+ return 0;
+}
+
+static int mlock_fixup(struct vm_area_struct * vma,
+ unsigned long start, unsigned long end, unsigned int newflags)
+{
+ int pages, retval;
+
+ if (newflags == vma->vm_flags)
+ return 0;
+
+ /* keep track of amount of locked VM */
+ pages = (end - start) >> PAGE_SHIFT;
+ if (!(newflags & VM_LOCKED))
+ pages = -pages;
+ vma->vm_mm->locked_vm += pages;
+
+ if (start == vma->vm_start) {
+ if (end == vma->vm_end)
+ retval = mlock_fixup_all(vma, newflags);
+ else
+ retval = mlock_fixup_start(vma, end, newflags);
+ } else {
+ if (end == vma->vm_end)
+ retval = mlock_fixup_end(vma, start, newflags);
+ else
+ retval = mlock_fixup_middle(vma, start, end, newflags);
+ }
+ if (!retval && (newflags & VM_LOCKED)) {
+ while (start < end) {
+ char c = get_user((char *) start);
+ __asm__ __volatile__("": :"r" (c));
+ start += PAGE_SIZE;
+ }
+ }
+ return retval;
+}
+
+static int do_mlock(unsigned long start, size_t len, int on)
+{
+ unsigned long nstart, end, tmp;
+ struct vm_area_struct * vma, * next;
+ int error;
+
+ if (!suser())
+ return -EPERM;
+ len = (len + ~PAGE_MASK) & PAGE_MASK;
+ end = start + len;
+ if (end < start)
+ return -EINVAL;
+ if (end == start)
+ return 0;
+ vma = find_vma(current, start);
+ if (!vma || vma->vm_start > start)
+ return -ENOMEM;
+
+ for (nstart = start ; ; ) {
+ unsigned int newflags;
+
+ /* Here we know that vma->vm_start <= nstart < vma->vm_end. */
+
+ newflags = vma->vm_flags | VM_LOCKED;
+ if (!on)
+ newflags &= ~VM_LOCKED;
+
+ if (vma->vm_end >= end) {
+ error = mlock_fixup(vma, nstart, end, newflags);
+ break;
+ }
+
+ tmp = vma->vm_end;
+ next = vma->vm_next;
+ error = mlock_fixup(vma, nstart, tmp, newflags);
+ if (error)
+ break;
+ nstart = tmp;
+ vma = next;
+ if (!vma || vma->vm_start != nstart) {
+ error = -ENOMEM;
+ break;
+ }
+ }
+ merge_segments(current, start, end);
+ return error;
+}
+
+asmlinkage int sys_mlock(unsigned long start, size_t len)
+{
+ unsigned long locked;
+ unsigned long lock_limit;
+
+ len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
+ start &= PAGE_MASK;
+
+ locked = len >> PAGE_SHIFT;
+ locked += current->mm->locked_vm;
+
+ lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ lock_limit >>= PAGE_SHIFT;
+
+ /* check against resource limits */
+ if (locked > lock_limit)
+ return -ENOMEM;
+
+ /* we may lock at most half of physical memory... */
+ /* (this check is pretty bogus, but doesn't hurt) */
+ if (locked > MAP_NR(high_memory)/2)
+ return -ENOMEM;
+
+ return do_mlock(start, len, 1);
+}
+
+asmlinkage int sys_munlock(unsigned long start, size_t len)
+{
+ len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
+ start &= PAGE_MASK;
+ return do_mlock(start, len, 0);
+}
+
+static int do_mlockall(int flags)
+{
+ int error;
+ unsigned int def_flags;
+ struct vm_area_struct * vma;
+
+ if (!suser())
+ return -EPERM;
+
+ def_flags = 0;
+ if (flags & MCL_FUTURE)
+ def_flags = VM_LOCKED;
+ current->mm->def_flags = def_flags;
+
+ error = 0;
+ for (vma = current->mm->mmap; vma ; vma = vma->vm_next) {
+ unsigned int newflags;
+
+ newflags = vma->vm_flags | VM_LOCKED;
+ if (!(flags & MCL_CURRENT))
+ newflags &= ~VM_LOCKED;
+ error = mlock_fixup(vma, vma->vm_start, vma->vm_end, newflags);
+ if (error)
+ break;
+ }
+ merge_segments(current, 0, TASK_SIZE);
+ return error;
+}
+
+asmlinkage int sys_mlockall(int flags)
+{
+ unsigned long lock_limit;
+
+ if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
+ return -EINVAL;
+
+ lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ lock_limit >>= PAGE_SHIFT;
+
+ if (current->mm->total_vm > lock_limit)
+ return -ENOMEM;
+
+ /* we may lock at most half of physical memory... */
+ /* (this check is pretty bogus, but doesn't hurt) */
+ if (current->mm->total_vm > MAP_NR(high_memory)/2)
+ return -ENOMEM;
+
+ return do_mlockall(flags);
+}
+
+asmlinkage int sys_munlockall(void)
+{
+ return do_mlockall(0);
+}
if (off + len < off)
return -EINVAL;
+ /* mlock MCL_FUTURE? */
+ if (current->mm->def_flags & VM_LOCKED) {
+ unsigned long locked = current->mm->locked_vm << PAGE_SHIFT;
+ locked += len;
+ if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
+ return -EAGAIN;
+ }
+
/*
* do simple checking here so the lower-level routines won't have
* to. we assume access permissions have been handled by the open
vma->vm_end = addr + len;
vma->vm_flags = prot & (VM_READ | VM_WRITE | VM_EXEC);
vma->vm_flags |= flags & (VM_GROWSDOWN | VM_DENYWRITE | VM_EXECUTABLE);
+ vma->vm_flags |= current->mm->def_flags;
if (file) {
if (file->f_mode & 1)
}
insert_vm_struct(current, vma);
merge_segments(current, vma->vm_start, vma->vm_end);
+ current->mm->total_vm += len >> PAGE_SHIFT;
+ if (vma->vm_flags & VM_LOCKED) {
+ unsigned long start = vma->vm_start;
+ unsigned long end = vma->vm_end;
+ current->mm->locked_vm += len >> PAGE_SHIFT;
+ while (start < end) {
+ char c = get_user((char *) start);
+ __asm__ __volatile__("": :"r" (c));
+ start += PAGE_SIZE;
+ }
+ }
return addr;
}
area->vm_start, area->vm_end, addr, end);
return;
}
+ area->vm_mm->total_vm -= len >> PAGE_SHIFT;
+ if (area->vm_flags & VM_LOCKED)
+ area->vm_mm->locked_vm -= len >> PAGE_SHIFT;
/* Unmapping the whole area */
if (addr == area->vm_start && end == area->vm_end) {
mpnt = mm->mmap;
mm->mmap = NULL;
mm->mmap_avl = NULL;
+ mm->rss = 0;
+ mm->total_vm = 0;
+ mm->locked_vm = 0;
while (mpnt) {
struct vm_area_struct * next = mpnt->vm_next;
if (mpnt->vm_ops) {
unsigned long end;
/* Don't swap out areas like shared memory which have their
- own separate swapping mechanism. */
- if (vma->vm_flags & VM_SHM)
+ own separate swapping mechanism or areas which are locked down */
+ if (vma->vm_flags & (VM_SHM | VM_LOCKED))
return 0;
- /* Don't swap out areas like shared memory which have their
- own separate swapping mechanism. */
- if (vma->vm_flags & VM_DONTSWAP)
- return 0;
-
end = vma->vm_end;
while (start < end) {
int result = swap_out_pgd(tsk, vma, pgdir, start, end, limit);
* Craig Schlenter : Don't modify permanent entry
* during arp_rcv.
* Russ Nelson : Tidied up a few bits.
+ * Alexey Kuznetsov: Major changes to caching and behaviour,
+ * eg intelligent arp probing and generation
+ * of host down events.
+ * Alan Cox : Missing unlock in device events.
*/
/* RFC1122 Status:
#include <linux/if_arp.h>
#include <linux/in.h>
#include <linux/mm.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/trdevice.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
#include <net/ip.h>
+#include <net/icmp.h>
#include <net/route.h>
#include <net/protocol.h>
#include <net/tcp.h>
-#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/arp.h>
#ifdef CONFIG_AX25
#include <net/netrom.h>
#endif
#endif
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+
+#include <stdarg.h>
/*
* This structure defines the ARP mapping cache. As long as we make changes
pentry = &entry->next; /* go to next entry */
}
}
+ arp_unlock();
return NOTIFY_DONE;
}
*/
else
{
+#if 0
/*
* FIXME: ICMP HOST UNREACHABLE should be
* sent in this situation. --ANK
skb->sk->err = EHOSTDOWN;
skb->sk->error_report(skb->sk);
}
+#else
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
+#endif
dev_kfree_skb(skb, FREE_WRITE);
}
}