D: Wrote SYS V IPC (part of standard kernel since 0.99.10)
N: Dario Ballabio
-E: dario@milano.europe.dg.com
+E: ballabio_dario@emc.com
+E: dario.ballabio@tiscalinet.it
+E: dario.ballabio@inwind.it
D: Author and maintainer of the Ultrastor 14F/34F SCSI driver
D: Author and maintainer of the EATA ISA/EISA/PCI SCSI driver
-S: Data General Corporation
+S: EMC Corporation
S: Milano
S: Italy
The module will be called visor.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
+USB Belkin and Paracom Single Port Serial Driver
+CONFIG_USB_SERIAL_BELKIN
+ Say Y here if you want to use a Belkin USB Serial single port
+ adaptor (F5U103 is one of the model numbers) or the Peracom single
+ port USB to serial adapter.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called belkin_sa.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt.
+
USB FTDI Single Port Serial Driver
CONFIG_USB_SERIAL_FTDI_SIO
Say Y here if you want to use a FTDI SIO single port USB to serial
The module will be called digi_acceleport.o. If you want to compile
it as a module, say M here and read Documentation/modules.txt.
+USB Empeg empeg-car Mark I/II Driver
+CONFIG_USB_SERIAL_EMPEG
+ Say Y here if you want to connect to your Empeg empeg-car Mark I/II
+ mp3 player via USB.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called empeg.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
USB Serial Converter verbose debug
CONFIG_USB_SERIAL_DEBUG
Say Y here if you want verbose debug messages from the USB Serial
module, say M here and read Documentation/modules.txt. Most people
will say N.
+Toshiba Laptop support
+CONFIG_TOSHIBA
+ If you intend to run this the kernel on a Toshiba portable say yes
+ here. This adds a driver to safely access the System Management
+ Mode of the CPU on Toshiba portables. The System Management Mode
+ is used to set the BIOS and power saving options on Toshiba portables.
+
+ For information on utilities to make use of this driver see the
+ Toshiba Linux utilities website at:
+ http://www.buzzard.org.uk/toshiba/
+
/dev/cpu/microcode - Intel P6 CPU microcode support
CONFIG_MICROCODE
If you say Y here and also to "/dev file system support" in the
first class of operations work on <type>atomic_t</type>
<filename class=headerfile>include/asm/atomic.h</filename>; this
- contains a signed integer (at least 32 bits long), and you must use
+ contains a signed integer (at least 24 bits long), and you must use
these functions to manipulate or read atomic_t variables.
<function>atomic_read()</function> and
<function>atomic_set()</function> get and set the counter,
</para>
<para>
- The second class of atomic operations is atomic bit operations,
- defined in
+ The second class of atomic operations is atomic bit operations on a
+ <type>long</type>, defined in
<filename class=headerfile>include/asm/bitops.h</filename>. These
operations generally take a pointer to the bit pattern, and a bit
<para>
It is possible to call these operations with bit indices greater
- than 31. The resulting behavior is strange on big-endian
+ than BITS_PER_LONG. The resulting behavior is strange on big-endian
platforms though so it is a good idea not to do this.
</para>
+
+ <para>
+ Note that the order of bits depends on the architecture, and in
+ particular, the bitfield passed to these operations must be at
+ least as large as a <type>long</type>.
+ </para>
</chapter>
<chapter id="symbols">
------------------------------------------------------------------------------
/proc/sys Terrehon Bowden <terrehon@pacbell.net> October 7 1999
Bodo Bauer <bb@ricochet.net>
+
+2.4.x update Jorge Nerin <comandante@zaralinux.com> November 14 2000
------------------------------------------------------------------------------
-Version 1.2 Kernel version 2.2.12
+Version 1.3 Kernel version 2.2.12
+ Kernel version 2.4.0-test11-pre4
------------------------------------------------------------------------------
Table of Contents
0.1 Introduction/Credits
------------------------
-This documentation is part of a soon (or so we hope) to be released book on
-the SuSE Linux distribution. As there is no complete documentation for the
-/proc file system and we've used many freely available sources to write these
-chapters, it seems only fair to give the work back to the Linux community.
-This work is based on the 2.2.* kernel version. I'm afraid it's still far from
-complete, but we hope it will be useful. As far as we know, it is the first
-'all-in-one' document about the /proc file system. It is focused on the Intel
-x86 hardware, so if you are looking for PPC, ARM, SPARC, APX, etc., features,
-you probably won't find what you are looking for. It also only covers IPv4
-networking, not IPv6 nor other protocols - sorry. But additions and patches
-are welcome and will be added to this document if you mail them to Bodo.
+This documentation is part of a soon (or so we hope) to be released book on
+the SuSE Linux distribution. As there is no complete documentation for the
+/proc file system and we've used many freely available sources to write these
+chapters, it seems only fair to give the work back to the Linux community.
+This work is based on the 2.2.* kernel version and the upcomming 2.4.*. I'm
+afraid it's still far from complete, but we hope it will be useful. As far as
+we know, it is the first 'all-in-one' document about the /proc file system. It
+is focused on the Intel x86 hardware, so if you are looking for PPC, ARM,
+SPARC, APX, etc., features, you probably won't find what you are looking for.
+It also only covers IPv4 networking, not IPv6 nor other protocols - sorry. But
+additions and patches are welcome and will be added to this document if you
+mail them to Bodo.
We'd like to thank Alan Cox, Rik van Riel, and Alexey Kuznetsov and a lot of
other people for help compiling this documentation. We'd also like to extend a
contact Bodo Bauer at bb@ricochet.net. We'll be happy to add them to this
document.
-The latest version of this document is available online at
+The latest version of this document is available online at
http://skaro.nightcrawler.com/~bb/Docs/Proc as HTML version.
+If the above direction does not works for you, ypu could try the kernel
+mailing list at linux-kernel@vger.kernel.org and/or try to reach me at
+comandante@zaralinux.com.
+
0.2 Legal Stuff
---------------
The proc file system acts as an interface to internal data structures in the
kernel. It can be used to obtain information about the system and to change
-certain kernel parameters at runtime.
+certain kernel parameters at runtime (sysctl).
First, we'll take a look at the read-only parts of /proc. In Chapter 2, we
show you how you can use /proc/sys to change settings.
..............................................................................
File Content
cmdline Command line arguments
- environ Values of environment variables
+ cpu Current and last cpu in wich it was executed (2.4)(smp)
+ cwd Link to the current working directory
+ environ Values of environment variables
+ exe Link to the executable of this process
fd Directory, which contains all file descriptors
+ maps Memory maps to executables and library files (2.4)
mem Memory held by this process
+ root Link to the root directory of this process
stat Process status
- status Process status in human readable form
- cwd Link to the current working directory
- exe Link to the executable of this process
- maps Memory maps
- root Link to the root directory of this process
statm Process memory status information
+ status Process status in human readable form
..............................................................................
For example, to get the status information of a process, all you have to do is
State: R (running)
Pid: 5452
PPid: 743
+ TracerPid: 0 (2.4)
Uid: 501 501 501 501
Gid: 100 100 100 100
Groups: 100 14 16
devices Available devices (block and character)
dma Used DMS channels
filesystems Supported filesystems
+ driver Various drivers grouped here, currently rtc (2.4)
+ execdomains Execdomains, related to security (2.4)
+ fb Frame Buffer devices (2.4)
+ fs File system parameters, currently nfs/exports (2.4)
ide Directory containing info about the IDE subsystem
interrupts Interrupt usage
+ iomem Memory map (2.4)
ioports I/O port usage
- kcore Kernel core image (can be ELF or A.OUT)
+ irq Masks for irq to cpu affinity (2.4)(smp?)
+ isapnp ISA PnP (Plug&Play) Info (2.4)
+ kcore Kernel core image (can be ELF or A.OUT(deprecated in 2.4))
kmsg Kernel messages
ksyms Kernel symbol table
- loadavg Load average
+ loadavg Load average of last 1, 5 & 15 minutes
locks Kernel locks
meminfo Memory info
misc Miscellaneous
mounts Mounted filesystems
net Networking info (see text)
partitions Table of partitions known to the system
+ pci Depreciated info of PCI bus (new way -> /proc/bus/pci/,
+ decoupled by lspci (2.4)
rtc Real time clock
scsi SCSI info (see text)
slabinfo Slab pool info
stat Overall statistics
swaps Swap space utilization
sys See chapter 2
+ sysvipc Info of SysVIPC Resources (msg, sem, shm) (2.4)
+ tty Info of tty drivers
uptime System uptime
version Kernel version
+ video bttv info of video resources (2.4)
..............................................................................
You can, for example, check which interrupts are currently in use and what
15: 7 XT-PIC ide1
NMI: 0
+In 2.4.* a couple of lines where added to this file LOC & ERR (this time is the
+output of a SMP machine):
+
+ > cat /proc/interrupts
+
+ CPU0 CPU1
+ 0: 1243498 1214548 IO-APIC-edge timer
+ 1: 8949 8958 IO-APIC-edge keyboard
+ 2: 0 0 XT-PIC cascade
+ 5: 11286 10161 IO-APIC-edge soundblaster
+ 8: 1 0 IO-APIC-edge rtc
+ 9: 27422 27407 IO-APIC-edge 3c503
+ 12: 113645 113873 IO-APIC-edge PS/2 Mouse
+ 13: 0 0 XT-PIC fpu
+ 14: 22491 24012 IO-APIC-edge ide0
+ 15: 2183 2415 IO-APIC-edge ide1
+ 17: 30564 30414 IO-APIC-level eth0
+ 18: 177 164 IO-APIC-level bttv
+ NMI: 2457961 2457959
+ LOC: 2457882 2457881
+ ERR: 2155
+
+NMI is incremented in this case because every timer interrupt generates a NMI
+(Non Maskable Interrupt) which is used by the NMI Watchdog to detect lookups.
+
+LOC is the local interrupt counter of the internal APIC of every CPU.
+
+ERR is incremented in the case of errors in the IO-APIC bus (the bus that
+connects the CPUs in a SMP system. This means that an error has been detected,
+the IO-APIC automatically retry the transmision, so it should not be a big
+problem, but you should read the SMP-FAQ.
+
+In this context it could be interesting to note the new irq directory in 2.4.
+It could be used to set IRQ to CPU affinity, this means that you can "hook" an
+IRQ to only one CPU, or to exclude a CPU of handling IRQs. The contents of the
+irq subdir is one subdir for each IRQ, and one file; prof_cpu_mask
+
+For example
+ > ls /proc/irq/
+ 0 10 12 14 16 18 2 4 6 8 prof_cpu_mask
+ 1 11 13 15 17 19 3 5 7 9
+ > ls /proc/irq/0/
+ smp_affinity
+
+The contents of the prof_cpu_mask file and each smp_affinity file for each IRQ
+is the same by default:
+
+ > cat /proc/irq/0/smp_affinity
+ ffffffff
+
+It's a bitmask, in wich you can specify wich CPUs can handle the IRQ, you can
+set it by doing:
+
+ > echo 1 > /proc/irq/prof_cpu_mask
+
+This means that only the first CPU will handle the IRQ, but you can also echo 5
+wich means that only the first and fourth CPU can handle the IRQ.
+
+The way IRQs are routed is handled by the IO-APIC, and it's Round Robin
+between all the CPUs which are allowed to handle it. As usual the kernel has
+more info than you and does a better job than you, so the defaults are the
+best choice for almost everyone.
There are three more important subdirectories in /proc: net, scsi, and sys.
The general rule is that the contents, or even the existence of these
TCP settings
------------
+tcp_ecn
+-------
+
+This file controls the use of the ECN bit in the IPv4 headers, this is a new
+feature about Explicit Congestion Notification, but some routers and firewalls
+block trafic that has this bit set, so it could be necessary to echo 0 to
+/proc/sys/net/ipv4/tcp_ecn, if you want to talk to this sites. For more info
+you could read RFC2481.
+
tcp_retrans_collapse
--------------------
To use the IrDA protocols within Linux you will need to get a suitable copy
of the IrDA Utilities. More detailed information about these and associated
-programs can be found on http://www.cs.uit.no/linux-irda/
+programs can be found on http://irda.sourceforge.net/
For more information about how to use the IrDA protocol stack, see the
-IR-HOWTO (http://www.snafu.de/~wehe/IR-HOWTO.html) written by Werner Heuser
-<wehe@snafu.de>
+IR-HOWTO (http://www.mobilix.org/Infrared-HOWTO/Infrared-HOWTO.html) written by Werner Heuser
+<wehe@mobilix.org>
There is an active mailing list for discussing Linux-IrDA matters called
linux-irda. To subscribe to it, visit:
-- Add everything else that is missing :)
+Empeg empeg-car Mark I/II Driver (empeg.c)
+
+ This is an experimental driver to provide connectivity support for the
+ client synchronization tools for an Empeg empeg-car mp3 player.
+
+ The driver is still pretty new, so some testing 'in the wild' would be
+ helpful. :)
+
+
Generic Serial driver
If your device is not one of the above listed devices, compatible with
EATA ISA/EISA/PCI SCSI DRIVER
P: Dario Ballabio
-M: dario@milano.europe.dg.com
+M: ballabio_dario@emc.com
L: linux-scsi@vger.kernel.org
S: Maintained
IRDA SUBSYSTEM
P: Dag Brattli
-M: Dag Brattli <dagb@cs.uit.no>
+M: Dag Brattli <dag@brattli.net>
L: linux-irda@pasta.cs.uit.no
-W: http://www.cs.uit.no/linux-irda/
+W: http://irda.sourceforge.net/
S: Maintained
ISAPNP
U14-34F SCSI DRIVER
P: Dario Ballabio
-M: dario@milano.europe.dg.com
+M: ballabio_dario@emc.com
L: linux-scsi@vger.kernel.org
S: Maintained
stat0 = *(vip)CIA_IOC_CIA_ERR;
*(vip)CIA_IOC_CIA_ERR = stat0;
mb();
+ *(vip)CIA_IOC_CIA_ERR; /* re-read to force write */
/* If Type1 access, must set CIA CFG. */
if (type1) {
*(vip)CIA_IOC_CFG;
}
+ mb();
draina();
mcheck_expected(0) = 1;
mcheck_taken(0) = 0;
stat0 = *(vip)CIA_IOC_CIA_ERR;
*(vip)CIA_IOC_CIA_ERR = stat0;
mb();
+ *(vip)CIA_IOC_CIA_ERR; /* re-read to force write */
/* If Type1 access, must set CIA CFG. */
if (type1) {
*(vip)CIA_IOC_CFG;
}
+ mb();
draina();
mcheck_expected(0) = 1;
mcheck_taken(0) = 0;
/* Access configuration space. */
*(vip)addr = value;
mb();
- mb(); /* magic */
+ *(vip)addr; /* read back to force the write */
mcheck_expected(0) = 0;
mb();
*(vip)CIA_IOC_ERR_MASK = temp;
/* Clear all currently pending errors. */
- *(vip)CIA_IOC_CIA_ERR = 0;
+ temp = *(vip)CIA_IOC_CIA_ERR;
+ *(vip)CIA_IOC_CIA_ERR = temp;
/* Turn on mchecks. */
temp = *(vip)CIA_IOC_CIA_CTRL;
/* 2.3.x PCI/resources, 1999 Andrea Arcangeli <andrea@suse.de> */
+/*
+ * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+ * PCI-PCI bridges cleanup
+ */
+
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/init.h>
dev->resource[3].end = dev->resource[3].start + 7;
}
+/*
+ * Notorious Cy82C693 chip. One of its numerous bugs: although
+ * Cypress IDE controller doesn't support native mode, it has
+ * programmable addresses of IDE command/control registers.
+ * This violates PCI specifications, confuses IDE subsystem
+ * and causes resource conflict between primary HD_CMD register
+ * and floppy controller. Ugh.
+ * Fix that.
+ */
+static void __init
+quirk_cypress_ide_ports(struct pci_dev *dev)
+{
+ if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE)
+ return;
+ dev->resource[1].start |= 2;
+ dev->resource[1].end = dev->resource[1].start;
+ pci_claim_resource(dev, 0);
+ pci_claim_resource(dev, 1);
+}
+
static void __init
quirk_vga_enable_rom(struct pci_dev *dev)
{
But if its a Cirrus 543x/544x DISABLE it, since
enabling ROM disables the memory... */
if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA &&
- /* But if its a Cirrus 543x/544x DISABLE it */
(dev->vendor != PCI_VENDOR_ID_CIRRUS ||
(dev->device < 0x00a0) || (dev->device > 0x00ac)))
{
quirk_isa_bridge },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229,
quirk_ali_ide_ports },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693,
+ quirk_cypress_ide_ports },
{ PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_vga_enable_rom },
{ 0 }
};
start = PCIBIOS_MIN_IO + hose->io_space->start;
/*
- * Aligning to 0x800 rather than the minimum base of
- * 0x400 is an attempt to avoid having devices in
- * any 0x?C?? range, which is where the de4x5 driver
- * probes for EISA cards.
- *
- * Adaptecs, especially, resent such intrusions.
- *
- * The de4x5 driver has the eisa probe conditionalized
- * out for Alpha, so lower the minimum base back to 0x400.
+ * Put everything into 0x00-0xff region modulo 0x400
*/
- alignto = MAX(0x400, size);
- start = ALIGN(start, alignto);
+ if (start & 0x300) {
+ start = (start + 0x3ff) & ~0x3ff;
+ res->start = start;
+ }
}
else if (res->flags & IORESOURCE_MEM) {
/* Make sure we start at our min on all hoses */
#undef MB
#undef GB
-/*
- * Pre-layout host-independant device initialization.
- */
-
-static void __init
-pcibios_assign_special(struct pci_dev * dev)
-{
- int i;
-
- /* The first three resources of an IDE controler are often magic,
- so leave them unchanged. This is true, for instance, of the
- Contaq 82C693 as seen on SX164 and DP264. */
-
- if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE) {
- /* Resource 1 of IDE controller is the address of HD_CMD
- register which actually occupies a single byte (0x3f6
- for ide0) in reported 0x3f4-3f7 range. We have to fix
- that to avoid resource conflict with AT-style floppy
- controller. */
- dev->resource[1].start += 2;
- dev->resource[1].end = dev->resource[1].start;
- for (i = 0; i < PCI_NUM_RESOURCES; i++)
- if (dev->resource[i].flags && dev->resource[i].start)
- pci_claim_resource(dev, i);
- }
- /*
- * We don't have code that will init the CYPRESS bridge correctly
- * so we do the next best thing, and depend on the previous
- * console code to do the right thing, and ignore it here... :-\
- */
- else if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
- dev->device == PCI_DEVICE_ID_CONTAQ_82C693)
- for (i = 0; i < PCI_NUM_RESOURCES; i++)
- if (dev->resource[i].flags && dev->resource[i].start)
- pci_claim_resource(dev, i);
-}
-
-
void __init
pcibios_init(void)
{
pcibios_fixup_resource(&dev->resource[i],
hose->mem_space);
}
- pcibios_assign_special(dev);
}
void __init
{
/* Propogate hose info into the subordinate devices. */
- struct pci_controler *hose = (struct pci_controler *) bus->sysdata;
+ struct pci_controler *hose = bus->sysdata;
struct list_head *ln;
+ struct pci_dev *dev = bus->self;
- /* ???? */
- bus->resource[0] = hose->io_space;
- bus->resource[1] = hose->mem_space;
+ if (!dev) {
+ /* Root bus */
+ bus->resource[0] = hose->io_space;
+ bus->resource[1] = hose->mem_space;
+ } else {
+ /* This is a bridge. Do not care how it's initialized,
+ just link its resources to the bus ones */
+ int i;
- /* If this is a bridge, get the current bases */
- if (bus->self) {
- pci_read_bridge_bases(bus);
- pcibios_fixup_device_resources(bus->self, bus->parent);
+ for(i=0; i<3; i++) {
+ bus->resource[i] =
+ &dev->resource[PCI_BRIDGE_RESOURCES+i];
+ bus->resource[i]->name = bus->name;
+ }
+ bus->resource[0]->flags |= pci_bridge_check_io(dev);
+ bus->resource[1]->flags |= IORESOURCE_MEM;
+ /* For now, propogate hose limits to the bus;
+ we'll adjust them later. */
+ bus->resource[0]->end = hose->io_space->end;
+ bus->resource[1]->end = hose->mem_space->end;
+ /* Turn off downstream PF memory address range by default */
+ bus->resource[2]->start = 1024*1024;
+ bus->resource[2]->end = bus->resource[2]->start - 1;
}
for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
}
-#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
-
-static void __init
-pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
-{
- struct pbus_set_ranges_data inner;
- struct pci_dev *dev;
- struct pci_dev *bridge = bus->self;
- struct pci_controler *hose = bus->sysdata;
- struct list_head *ln;
-
- if (!bridge)
- return; /* host bridge, nothing to do */
-
- /* set reasonable default locations for pcibios_align_resource */
- inner.io_start = hose->io_space->start + PCIBIOS_MIN_IO;
- inner.mem_start = hose->mem_space->start + PCIBIOS_MIN_MEM;
- inner.io_end = inner.io_start;
- inner.mem_end = inner.mem_start;
-
- /* Collect information about how our direct children are layed out. */
- for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
- int i;
- dev = pci_dev_b(ln);
-
- /* Skip bridges for now */
- if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
- continue;
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource res;
- unsigned long size;
-
- memcpy(&res, &dev->resource[i], sizeof(res));
- size = res.end - res.start + 1;
-
- if (res.flags & IORESOURCE_IO) {
- res.start = inner.io_end;
- pcibios_align_resource(dev, &res, size);
- inner.io_end = res.start + size;
- } else if (res.flags & IORESOURCE_MEM) {
- res.start = inner.mem_end;
- pcibios_align_resource(dev, &res, size);
- inner.mem_end = res.start + size;
- }
- }
- }
-
- /* And for all of the subordinate busses. */
- for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
- pcibios_size_bridge(pci_bus_b(ln), &inner);
-
- /* turn the ending locations into sizes (subtract start) */
- inner.io_end -= inner.io_start;
- inner.mem_end -= inner.mem_start;
-
- /* Align the sizes up by bridge rules */
- inner.io_end = ROUND_UP(inner.io_end, 4*1024) - 1;
- inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024) - 1;
-
- /* Adjust the bridge's allocation requirements */
- bridge->resource[0].end = bridge->resource[0].start + inner.io_end;
- bridge->resource[1].end = bridge->resource[1].start + inner.mem_end;
-
- bridge->resource[PCI_BRIDGE_RESOURCES].end =
- bridge->resource[PCI_BRIDGE_RESOURCES].start + inner.io_end;
- bridge->resource[PCI_BRIDGE_RESOURCES+1].end =
- bridge->resource[PCI_BRIDGE_RESOURCES+1].start + inner.mem_end;
-
- /* adjust parent's resource requirements */
- if (outer) {
- outer->io_end = ROUND_UP(outer->io_end, 4*1024);
- outer->io_end += inner.io_end;
-
- outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024);
- outer->mem_end += inner.mem_end;
- }
-}
-
-#undef ROUND_UP
-
-static void __init
-pcibios_size_bridges(void)
-{
- struct list_head *ln1, *ln2;
-
- for(ln1=pci_root_buses.next; ln1 != &pci_root_buses; ln1=ln1->next)
- for(ln2 = pci_bus_b(ln1)->children.next;
- ln2 != &pci_bus_b(ln1)->children;
- ln2 = ln2->next)
- pcibios_size_bridge(pci_bus_b(ln2), NULL);
-}
-
void __init
common_init_pci(void)
{
next_busno += 1;
}
- pcibios_size_bridges();
pci_assign_unassigned_resources();
pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
- pci_set_bus_ranges();
}
init_i8259a_irqs();
- /* Not interested in the bogus interrupts (0,3,4,6),
+ /* Not interested in the bogus interrupts (0,3,6),
NMI (1), HALT (2), flash (5), or 21142 (8). */
- init_pyxis_irqs(0x17f0000);
+ init_pyxis_irqs(0x16f0000);
common_init_isa_dma();
}
*/
pci_assign_unassigned_resources();
pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq);
- pci_set_bus_ranges();
}
char * __init pcibios_setup(char *str)
}
} /* End Function have_wrcomb */
+static u32 size_or_mask, size_and_mask;
+
static void intel_get_mtrr (unsigned int reg, unsigned long *base,
unsigned long *size, mtrr_type *type)
{
- unsigned long dummy, mask_lo, base_lo;
+ unsigned long mask_lo, mask_hi, base_lo, base_hi;
- rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
+ rdmsr (MTRRphysMask_MSR(reg), mask_lo, mask_hi);
if ( (mask_lo & 0x800) == 0 )
{
/* Invalid (i.e. free) range */
return;
}
- rdmsr(MTRRphysBase_MSR(reg), base_lo, dummy);
+ rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
- /* We ignore the extra address bits (32-35). If someone wants to
- run x86 Linux on a machine with >4GB memory, this will be the
- least of their problems. */
+ /* Work out the shifted address mask. */
+ mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT)
+ | mask_lo >> PAGE_SHIFT;
- /* Clean up mask_lo so it gives the real address mask. */
- mask_lo = (mask_lo & 0xfffff000UL);
/* This works correctly if size is a power of two, i.e. a
contiguous range. */
- *size = ~(mask_lo - 1);
-
- *base = (base_lo & 0xfffff000UL);
- *type = (base_lo & 0xff);
+ *size = -mask_lo;
+ *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
+ *type = base_lo & 0xff;
} /* End Function intel_get_mtrr */
static void cyrix_get_arr (unsigned int reg, unsigned long *base,
/* Enable interrupts if it was enabled previously */
__restore_flags (flags);
shift = ((unsigned char *) base)[1] & 0x0f;
- *base &= 0xfffff000UL;
+ *base >>= PAGE_SHIFT;
/* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
* Note: shift==0xf means 4G, this is unsupported.
*/
if (shift)
- *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift;
+ *size = (reg < 7 ? 0x1UL : 0x40UL) << shift;
else
*size = 0;
/* Upper dword is region 1, lower is region 0 */
if (reg == 1) low = high;
/* The base masks off on the right alignment */
- *base = low & 0xFFFE0000;
+ *base = (low & 0xFFFE0000) >> PAGE_SHIFT;
*type = 0;
if (low & 1) *type = MTRR_TYPE_UNCACHABLE;
if (low & 2) *type = MTRR_TYPE_WRCOMB;
* *128K ...
*/
low = (~low) & 0x1FFFC;
- *size = (low + 4) << 15;
+ *size = (low + 4) << (15 - PAGE_SHIFT);
return;
} /* End Function amd_get_mtrr */
static void centaur_get_mcr (unsigned int reg, unsigned long *base,
unsigned long *size, mtrr_type *type)
{
- *base = centaur_mcr[reg].high & 0xfffff000;
- *size = (~(centaur_mcr[reg].low & 0xfffff000))+1;
+ *base = centaur_mcr[reg].high >> PAGE_SHIFT;
+ *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
*type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */
} /* End Function centaur_get_mcr */
}
else
{
- wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
- wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
+ wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type,
+ (base & size_and_mask) >> (32 - PAGE_SHIFT));
+ wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800,
+ (-size & size_and_mask) >> (32 - PAGE_SHIFT));
}
if (do_safe) set_mtrr_done (&ctxt);
} /* End Function intel_set_mtrr_up */
arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
/* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
- size >>= (reg < 7 ? 12 : 18);
+ if (reg >= 7)
+ size >>= 6;
+
size &= 0x7fff; /* make sure arr_size <= 14 */
for(arr_size = 0; size; arr_size++, size >>= 1);
}
if (do_safe) set_mtrr_prepare (&ctxt);
+ base <<= PAGE_SHIFT;
setCx86(arr, ((unsigned char *) &base)[3]);
setCx86(arr+1, ((unsigned char *) &base)[2]);
setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);
[RETURNS] Nothing.
*/
{
- u32 low, high;
+ u32 regs[2];
struct set_mtrr_context ctxt;
if (do_safe) set_mtrr_prepare (&ctxt);
/*
* Low is MTRR0 , High MTRR 1
*/
- rdmsr (0xC0000085, low, high);
+ rdmsr (0xC0000085, regs[0], regs[1]);
/*
* Blank to disable
*/
if (size == 0)
- *(reg ? &high : &low) = 0;
+ regs[reg] = 0;
else
- /* Set the register to the base (already shifted for us), the
- type (off by one) and an inverted bitmask of the size
- The size is the only odd bit. We are fed say 512K
- We invert this and we get 111 1111 1111 1011 but
- if you subtract one and invert you get the desired
- 111 1111 1111 1100 mask
- */
- *(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
+ /* Set the register to the base, the type (off by one) and an
+ inverted bitmask of the size The size is the only odd
+ bit. We are fed say 512K We invert this and we get 111 1111
+ 1111 1011 but if you subtract one and invert you get the
+ desired 111 1111 1111 1100 mask
+
+ But ~(x - 1) == ~x + 1 == -x. Two's complement rocks! */
+ regs[reg] = (-size>>(15-PAGE_SHIFT) & 0x0001FFFC)
+ | (base<<PAGE_SHIFT) | (type+1);
+
/*
* The writeback rule is quite specific. See the manual. Its
* disable local interrupts, write back the cache, set the mtrr
*/
__asm__ __volatile__ ("wbinvd" : : : "memory");
- wrmsr (0xC0000085, low, high);
+ wrmsr (0xC0000085, regs[0], regs[1]);
if (do_safe) set_mtrr_done (&ctxt);
} /* End Function amd_set_mtrr_up */
}
else
{
- high = base & 0xfffff000; /* base works on 4K pages... */
- low = ((~(size-1))&0xfffff000);
- low |= 0x1f; /* only support write-combining... */
+ high = base << PAGE_SHIFT;
+ low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */
}
centaur_mcr[reg].high = high;
centaur_mcr[reg].low = low;
for (i = 0; i < max; ++i)
{
(*get_mtrr) (i, &lbase, &lsize, <ype);
- if (lsize < 1) return i;
+ if (lsize == 0) return i;
}
return -ENOSPC;
} /* End Function generic_get_free_region */
unsigned long lbase, lsize;
/* If we are to set up a region >32M then look at ARR7 immediately */
- if (size > 0x2000000UL)
+ if (size > 0x2000)
{
cyrix_get_arr (7, &lbase, &lsize, <ype);
- if (lsize < 1) return 7;
+ if (lsize == 1) return 7;
/* Else try ARR0-ARR6 first */
}
else
{
cyrix_get_arr (i, &lbase, &lsize, <ype);
if ((i == 3) && arr3_protected) continue;
- if (lsize < 1) return i;
+ if (lsize == 0) return i;
}
/* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
cyrix_get_arr (i, &lbase, &lsize, <ype);
- if ((lsize < 1) && (size >= 0x40000)) return i;
+ if ((lsize == 0) && (size >= 0x40)) return i;
}
return -ENOSPC;
} /* End Function cyrix_get_free_region */
unsigned long size) = generic_get_free_region;
/**
- * mtrr_add - Add a memory type region
- * @base: Physical base address of region
- * @size: Physical size of region
+ * mtrr_add_page - Add a memory type region
+ * @base: Physical base address of region in pages (4 KB)
+ * @size: Physical size of region in pages (4 KB)
* @type: Type of MTRR desired
* @increment: If this is true do usage counting on the region
*
* failures and do not wish system log messages to be sent.
*/
-int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment)
+int mtrr_add_page(unsigned long base, unsigned long size, unsigned int type, char increment)
{
/* [SUMMARY] Add an MTRR entry.
- <base> The starting (base) address of the region.
- <size> The size (in bytes) of the region.
+ <base> The starting (base, in pages) address of the region.
+ <size> The size of the region. (in pages)
<type> The type of the new region.
<increment> If true and the region already exists, the usage count will be
incremented.
o Power of 2 block
o base suitably aligned to the power
*/
- if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+ if ( type > MTRR_TYPE_WRCOMB || size < (1 << (17-PAGE_SHIFT)) ||
(size & ~(size-1))-size || ( base & (size-1) ) )
return -EINVAL;
break;
boot_cpu_data.x86_model == 1 &&
boot_cpu_data.x86_mask <= 7 )
{
- if ( base & ((1 << 22)-1) )
+ if ( base & ((1 << (22-PAGE_SHIFT))-1) )
{
- printk (KERN_WARNING "mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
+ printk (KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
return -EINVAL;
}
}
case MTRR_IF_CYRIX_ARR:
case MTRR_IF_CENTAUR_MCR:
- if ( (base & 0xfff) || (size & 0xfff) )
- {
- printk ("mtrr: size and base must be multiples of 4 kiB\n");
- printk ("mtrr: size: %lx base: %lx\n", size, base);
- return -EINVAL;
- }
if ( mtrr_if == MTRR_IF_CENTAUR_MCR )
{
if (type != MTRR_TYPE_WRCOMB)
return -EINVAL;
}
}
- else if (base + size < 0x100000)
+ else if (base + size < 0x100)
{
- printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
+ printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n",
base, size);
return -EINVAL;
}
lbase = lbase >> 1, last = last >> 1);
if (lbase != last)
{
- printk (KERN_WARNING "mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
+ printk (KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n",
base, size);
return -EINVAL;
}
printk ("mtrr: type: %u illegal\n", type);
return -EINVAL;
}
+
/* If the type is WC, check that this processor supports it */
if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () )
{
printk (KERN_WARNING "mtrr: your processor doesn't support write-combining\n");
return -ENOSYS;
}
+
+ if ( base & size_or_mask || size & size_or_mask )
+ {
+ printk ("mtrr: base or size exceeds the MTRR width\n");
+ return -EINVAL;
+ }
+
increment = increment ? 1 : 0;
max = get_num_var_ranges ();
/* Search for existing MTRR */
if ( (base < lbase) || (base + size > lbase + lsize) )
{
up(&main_lock);
- printk (KERN_WARNING "mtrr: 0x%lx,0x%lx overlaps existing 0x%lx,0x%lx\n",
+ printk (KERN_WARNING "mtrr: 0x%lx000,0x%lx000 overlaps existing"
+ " 0x%lx000,0x%lx000\n",
base, size, lbase, lsize);
return -EINVAL;
}
{
if (type == MTRR_TYPE_UNCACHABLE) continue;
up(&main_lock);
- printk ( "mtrr: type mismatch for %lx,%lx old: %s new: %s\n",
+ printk ( "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
base, size, attrib_to_str (ltype), attrib_to_str (type) );
return -EINVAL;
}
compute_ascii ();
up(&main_lock);
return i;
+} /* End Function mtrr_add_page */
+
+/**
+ * mtrr_add - Add a memory type region
+ * @base: Physical base address of region
+ * @size: Physical size of region
+ * @type: Type of MTRR desired
+ * @increment: If this is true do usage counting on the region
+ *
+ * Memory type region registers control the caching on newer Intel and
+ * non Intel processors. This function allows drivers to request an
+ * MTRR is added. The details and hardware specifics of each processor's
+ * implementation are hidden from the caller, but nevertheless the
+ * caller should expect to need to provide a power of two size on an
+ * equivalent power of two boundary.
+ *
+ * If the region cannot be added either because all regions are in use
+ * or the CPU cannot support it a negative value is returned. On success
+ * the register number for this entry is returned, but should be treated
+ * as a cookie only.
+ *
+ * On a multiprocessor machine the changes are made to all processors.
+ * This is required on x86 by the Intel processors.
+ *
+ * The available types are
+ *
+ * %MTRR_TYPE_UNCACHEABLE - No caching
+ *
+ * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever
+ *
+ * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts
+ *
+ * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes
+ *
+ * BUGS: Needs a quiet flag for the cases where drivers do not mind
+ * failures and do not wish system log messages to be sent.
+ */
+
+int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment)
+{
+/* [SUMMARY] Add an MTRR entry.
+ <base> The starting (base) address of the region.
+ <size> The size (in bytes) of the region.
+ <type> The type of the new region.
+ <increment> If true and the region already exists, the usage count will be
+ incremented.
+ [RETURNS] The MTRR register on success, else a negative number indicating
+ the error code.
+*/
+
+ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment);
} /* End Function mtrr_add */
/**
- * mtrr_del - delete a memory type region
+ * mtrr_del_page - delete a memory type region
* @reg: Register returned by mtrr_add
* @base: Physical base address
* @size: Size of region
* code.
*/
-int mtrr_del (int reg, unsigned long base, unsigned long size)
+int mtrr_del_page (int reg, unsigned long base, unsigned long size)
/* [SUMMARY] Delete MTRR/decrement usage count.
<reg> The register. If this is less than 0 then <<base>> and <<size>> must
be supplied.
for (i = 0; i < max; ++i)
{
(*get_mtrr) (i, &lbase, &lsize, <ype);
- if ( (lbase == base) && (lsize == size) )
+ if (lbase == base && lsize == size)
{
reg = i;
break;
if (reg < 0)
{
up(&main_lock);
- printk ("mtrr: no MTRR for %lx,%lx found\n", base, size);
+ printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size);
return -EINVAL;
}
}
compute_ascii ();
up (&main_lock);
return reg;
-} /* End Function mtrr_del */
+} /* End Function mtrr_del_page */
+
+/**
+ * mtrr_del - delete a memory type region
+ * @reg: Register returned by mtrr_add
+ * @base: Physical base address
+ * @size: Size of region
+ *
+ * If register is supplied then base and size are ignored. This is
+ * how drivers should call it.
+ *
+ * Releases an MTRR region. If the usage count drops to zero the
+ * register is freed and the region returns to default state.
+ * On success the register is returned, on failure a negative error
+ * code.
+ */
+
+int mtrr_del (int reg, unsigned long base, unsigned long size)
+/* [SUMMARY] Delete MTRR/decrement usage count.
+ <reg> The register. If this is less than 0 then <<base>> and <<size>> must
+ be supplied.
+ <base> The base address of the region. This is ignored if <<reg>> is >= 0.
+ <size> The size of the region. This is ignored if <<reg>> is >= 0.
+ [RETURNS] The register on success, else a negative number indicating
+ the error code.
+*/
+{
+ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
+}
#ifdef USERSPACE_INTERFACE
static int mtrr_file_add (unsigned long base, unsigned long size,
- unsigned int type, char increment, struct file *file)
+ unsigned int type, char increment, struct file *file, int page)
{
int reg, max;
unsigned int *fcount = file->private_data;
memset (fcount, 0, max * sizeof *fcount);
file->private_data = fcount;
}
- reg = mtrr_add (base, size, type, 1);
+ if (!page) {
+ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ base >>= PAGE_SHIFT;
+ size >>= PAGE_SHIFT;
+ }
+ reg = mtrr_add_page (base, size, type, 1);
if (reg >= 0) ++fcount[reg];
return reg;
} /* End Function mtrr_file_add */
static int mtrr_file_del (unsigned long base, unsigned long size,
- struct file *file)
+ struct file *file, int page)
{
int reg;
unsigned int *fcount = file->private_data;
- reg = mtrr_del (-1, base, size);
+ if (!page) {
+ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ base >>= PAGE_SHIFT;
+ size >>= PAGE_SHIFT;
+ }
+ reg = mtrr_del_page (-1, base, size);
if (reg < 0) return reg;
if (fcount == NULL) return reg;
if (fcount[reg] < 1) return -EINVAL;
static ssize_t mtrr_write (struct file *file, const char *buf, size_t len,
loff_t *ppos)
/* Format of control line:
- "base=%lx size=%lx type=%s" OR:
+ "base=%Lx size=%Lx type=%s" OR:
"disable=%d"
*/
{
int i, err;
- unsigned long reg, base, size;
+ unsigned long reg;
+ unsigned long long base, size;
char *ptr;
char line[LINE_SIZE];
if ( !strncmp (line, "disable=", 8) )
{
reg = simple_strtoul (line + 8, &ptr, 0);
- err = mtrr_del (reg, 0, 0);
+ err = mtrr_del_page (reg, 0, 0);
if (err < 0) return err;
return len;
}
printk ("mtrr: no \"base=\" in line: \"%s\"\n", line);
return -EINVAL;
}
- base = simple_strtoul (line + 5, &ptr, 0);
+ base = simple_strtoull (line + 5, &ptr, 0);
for (; isspace (*ptr); ++ptr);
if ( strncmp (ptr, "size=", 5) )
{
printk ("mtrr: no \"size=\" in line: \"%s\"\n", line);
return -EINVAL;
}
- size = simple_strtoul (ptr + 5, &ptr, 0);
+ size = simple_strtoull (ptr + 5, &ptr, 0);
+ if ( (base & 0xfff) || (size & 0xfff) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%Lx base: 0x%Lx\n", size, base);
+ return -EINVAL;
+ }
for (; isspace (*ptr); ++ptr);
if ( strncmp (ptr, "type=", 5) )
{
for (i = 0; i < MTRR_NUM_TYPES; ++i)
{
if ( strcmp (ptr, mtrr_strings[i]) ) continue;
- err = mtrr_add (base, size, i, 1);
+ base >>= PAGE_SHIFT;
+ size >>= PAGE_SHIFT;
+ err = mtrr_add_page ((unsigned long)base, (unsigned long)size, i, 1);
if (err < 0) return err;
return len;
}
if ( !suser () ) return -EPERM;
if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
return -EFAULT;
- err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file);
+ err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0);
if (err < 0) return err;
break;
case MTRRIOC_SET_ENTRY:
if ( !suser () ) return -EPERM;
if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
return -EFAULT;
- err = mtrr_file_del (sentry.base, sentry.size, file);
+ err = mtrr_file_del (sentry.base, sentry.size, file, 0);
if (err < 0) return err;
break;
case MTRRIOC_KILL_ENTRY:
return -EFAULT;
if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
+
+ /* Hide entries that go above 4GB */
+ if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000)
+ gentry.base = gentry.size = gentry.type = 0;
+ else {
+ gentry.base <<= PAGE_SHIFT;
+ gentry.size <<= PAGE_SHIFT;
+ gentry.type = type;
+ }
+
+ if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
+ return -EFAULT;
+ break;
+ case MTRRIOC_ADD_PAGE_ENTRY:
+ if ( !suser () ) return -EPERM;
+ if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+ return -EFAULT;
+ err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 1);
+ if (err < 0) return err;
+ break;
+ case MTRRIOC_SET_PAGE_ENTRY:
+ if ( !suser () ) return -EPERM;
+ if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+ return -EFAULT;
+ err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0);
+ if (err < 0) return err;
+ break;
+ case MTRRIOC_DEL_PAGE_ENTRY:
+ if ( !suser () ) return -EPERM;
+ if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+ return -EFAULT;
+ err = mtrr_file_del (sentry.base, sentry.size, file, 1);
+ if (err < 0) return err;
+ break;
+ case MTRRIOC_KILL_PAGE_ENTRY:
+ if ( !suser () ) return -EPERM;
+ if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+ return -EFAULT;
+ err = mtrr_del_page (-1, sentry.base, sentry.size);
+ if (err < 0) return err;
+ break;
+ case MTRRIOC_GET_PAGE_ENTRY:
+ if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
+ return -EFAULT;
+ if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
+ (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
gentry.type = type;
+
if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
return -EFAULT;
break;
for (i = 0; i < max; i++)
{
(*get_mtrr) (i, &base, &size, &type);
- if (size < 1) usage_table[i] = 0;
+ if (size == 0) usage_table[i] = 0;
else
{
- if (size < 0x100000)
+ if (size < (0x100000 >> PAGE_SHIFT))
{
- /* 1MB */
- factor = 'k';
- size >>= 10;
+ /* less than 1MB */
+ factor = 'K';
+ size <<= PAGE_SHIFT - 10;
}
else
{
factor = 'M';
- size >>= 20;
+ size >>= 20 - PAGE_SHIFT;
}
sprintf
(ascii_buffer + ascii_buf_bytes,
- "reg%02i: base=0x%08lx (%4liMB), size=%4li%cB: %s, count=%d\n",
- i, base, base>>20, size, factor,
+ "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n",
+ i, base, base >> (20 - PAGE_SHIFT), size, factor,
attrib_to_str (type), usage_table[i]);
ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
}
mtrr_if = MTRR_IF_INTEL;
get_mtrr = intel_get_mtrr;
set_mtrr_up = intel_set_mtrr_up;
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_AMD:
+ /* The original Athlon docs said that
+ total addressable memory is 44 bits wide.
+ It was not really clear whether its MTRRs
+ follow this or not. (Read: 44 or 36 bits).
+ However, "x86-64_overview.pdf" explicitly
+ states that "previous implementations support
+ 36 bit MTRRs" and also provides a way to
+ query the width (in bits) of the physical
+ addressable memory on the Hammer family.
+ */
+ if (boot_cpu_data.x86 == 7 && (cpuid_eax(0x80000000) >= 0x80000008)) {
+ u32 phys_addr;
+ phys_addr = cpuid_eax(0x80000008) & 0xff ;
+ size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
+ size_and_mask = ~size_or_mask & 0xfff00000;
+ break;
+ }
+ default:
+ /* Intel, etc. */
+ size_or_mask = 0xff000000; /* 36 bits */
+ size_and_mask = 0x00f00000;
+ break;
+ }
} else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) {
/* Pre-Athlon (K6) AMD CPU MTRRs */
mtrr_if = MTRR_IF_AMD_K6;
get_mtrr = amd_get_mtrr;
set_mtrr_up = amd_set_mtrr_up;
+ size_or_mask = 0xfff00000; /* 32 bits */
+ size_and_mask = 0;
} else if ( test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ) {
/* Cyrix ARRs */
mtrr_if = MTRR_IF_CYRIX_ARR;
set_mtrr_up = cyrix_set_arr_up;
get_free_region = cyrix_get_free_region;
cyrix_arr_init();
+ size_or_mask = 0xfff00000; /* 32 bits */
+ size_and_mask = 0;
} else if ( test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) {
/* Centaur MCRs */
mtrr_if = MTRR_IF_CENTAUR_MCR;
get_mtrr = centaur_get_mcr;
set_mtrr_up = centaur_set_mcr_up;
centaur_mcr_init();
+ size_or_mask = 0xfff00000; /* 32 bits */
+ size_and_mask = 0;
} else {
/* No supported MTRR interface */
mtrr_if = MTRR_IF_NONE;
dh = des >> 4;
dl = des & 0x0F;
+ /* Black magic... */
+
switch ( dh )
{
+ case 0:
+ switch ( dl ) {
+ case 6:
+ /* L1 I cache */
+ l1i += 8;
+ break;
+ case 8:
+ /* L1 I cache */
+ l1i += 16;
+ break;
+ case 10:
+ /* L1 D cache */
+ l1d += 8;
+ break;
+ case 12:
+ /* L1 D cache */
+ l1d += 16;
+ break;
+ default:
+ /* TLB, or unknown */
+ }
+ break;
case 2:
if ( dl ) {
/* L3 cache */
}
break;
case 4:
+ if ( c->x86 > 6 && dl ) {
+ /* P4 family */
+ if ( dl ) {
+ /* L3 cache */
+ cs = 128 << (dl-1);
+ l3 += cs;
+ break;
+ }
+ }
+ /* else same as 8 - fall through */
case 8:
if ( dl ) {
/* L2 cache */
}
break;
case 7:
- /* L1 I cache */
- cs = dl ? (16 << (dl-1)) : 12;
- l1i += cs;
+ if ( dl >= 8 )
+ {
+ /* L2 cache */
+ cs = 64<<(dl-8);
+ l2 += cs;
+ } else {
+ /* L0 I cache, count as L1 */
+ cs = dl ? (16 << (dl-1)) : 12;
+ l1i += cs;
+ }
break;
default:
/* TLB, or something else we don't know about */
/* Intel-defined */
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", "pn", "clflsh", NULL, "dtes", "acpi", "mmx",
- "fxsr", "sse", "sse2", "selfsnoop", NULL, "acc", "ia64", NULL,
+ "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL,
/* AMD-defined */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
EXPORT_SYMBOL(amiga_audio_min_period);
EXPORT_SYMBOL(amiga_do_irq);
EXPORT_SYMBOL(amiga_do_irq_list);
-EXPORT_SYMBOL(amiga_intena_vals);
#ifdef CONFIG_AMIGA_PCMCIA
EXPORT_SYMBOL(pcmcia_reset);
/* irq node variables for amiga interrupt sources */
static irq_node_t *ami_irq_list[AMI_STD_IRQS];
-unsigned short amiga_intena_vals[AMI_STD_IRQS] = {
+static unsigned short amiga_intena_vals[AMI_STD_IRQS] = {
IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER
};
/* turn off PCMCIA interrupts */
if (AMIGAHW_PRESENT(PCMCIA))
- pcmcia_disable_irq();
+ gayle.inten = GAYLE_IRQ_IDE;
/* turn off all interrupts and enable the master interrupt bit */
custom.intena = 0x7fff;
ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp);
}
-void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
+void amiga_do_irq_list(int irq, struct pt_regs *fp)
{
- irq_node_t *node, *slow_nodes;
- unsigned short flags, intena;
+ irq_node_t *node;
kstat.irqs[0][SYS_IRQS + irq]++;
- if (server->count++)
- server->reentrance = 1;
-
- intena = amiga_intena_vals[irq];
- custom.intreq = intena;
-
- /* serve fast handler if present - there can only be one of these */
- node = ami_irq_list[irq];
- /*
- * Timer interrupts show up like this
- */
- if (!node) {
- server->count--;
- return;
- }
+ custom.intreq = amiga_intena_vals[irq];
- if (node && (node->flags & SA_INTERRUPT)) {
- save_flags(flags);
- cli();
+ for (node = ami_irq_list[irq]; node; node = node->next)
node->handler(irq, node->dev_id, fp);
- restore_flags(flags);
-
- server->count--;
- return;
- }
-
- /*
- * Disable the interrupt source in question and reenable all
- * other interrupts. No interrupt handler should ever touch
- * the intena flags directly!
- */
- custom.intena = intena;
- save_flags(flags);
-#if 0 /* def CPU_M68060_ONLY */
- sti();
-#else
- restore_flags((flags & ~0x0700) | (fp->sr & 0x0700));
-#endif
-
- slow_nodes = node;
- for (;;) {
- for (; node; node = node->next)
- node->handler(irq, node->dev_id, fp);
-
- if (!server->reentrance) {
- server->count--;
- restore_flags(flags);
- custom.intena = IF_SETCLR | intena;
- return;
- }
-
- server->reentrance = 0;
- node = slow_nodes;
- }
}
/*
static void ami_int3(int irq, void *dev_id, struct pt_regs *fp)
{
unsigned short ints = custom.intreqr & custom.intenar;
- static struct irq_server server = {0, 0};
/* if a blitter interrupt */
if (ints & IF_BLIT) {
/* if a vertical blank interrupt */
if (ints & IF_VERTB)
- amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server);
+ amiga_do_irq_list(IRQ_AMIGA_VERTB, fp);
}
static void ami_int4(int irq, void *dev_id, struct pt_regs *fp)
* for more details.
*/
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/init.h>
void __init amiga_init_sound(void)
{
- snd_data = amiga_chip_alloc(sizeof(sine_data), "Beep");
+ static struct resource beep_res = { "Beep" };
+
+ snd_data = amiga_chip_alloc_res(sizeof(sine_data), &beep_res);
if (!snd_data) {
printk (KERN_CRIT "amiga init_sound: failed to allocate chipmem\n");
return;
/* setup divisor */
clock_constant = (amiga_colorclock+DATA_SIZE/2)/DATA_SIZE;
+
+ /* without amifb, turn video off and enable high quality sound */
+#ifndef CONFIG_FB_AMIGA
+ amifb_video_off();
+#endif
}
static void nosound( unsigned long ignored );
**
** Modified 03-May-94 by Geert Uytterhoeven <geert@linux-m68k.org>
** - 64-bit aligned allocations for full AGA compatibility
+**
+** Rewritten 15/9/2000 by Geert to use resource management
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ioport.h>
+#include <linux/slab.h>
#include <asm/amigahw.h>
-struct chip_desc {
- unsigned first : 1;
- unsigned last : 1;
- unsigned alloced : 1;
- unsigned length : 24;
- long pad; /* We suppose this makes this struct 64 bits long!! */
-};
-
-#define DP(ptr) ((struct chip_desc *)(ptr))
+unsigned long amiga_chip_size;
-u_long amiga_chip_size;
+static struct resource chipram_res = { "Chip RAM", CHIP_PHYSADDR };
static unsigned long chipavail;
-static struct resource chipram = { "Chip RAM", 0 };
-unsigned long amiga_chip_avail( void )
+void __init amiga_chip_init(void)
{
-#ifdef DEBUG
- printk("chip_avail : %ld bytes\n",chipavail);
+ if (!AMIGAHW_PRESENT(CHIP_RAM))
+ return;
+
+#ifndef CONFIG_APUS_FAST_EXCEPT
+ /*
+ * Remove the first 4 pages where PPC exception handlers will be located
+ */
+ amiga_chip_size -= 0x4000;
#endif
- return chipavail;
-}
+ chipram_res.end = amiga_chip_size-1;
+ request_resource(&iomem_resource, &chipram_res);
+ chipavail = amiga_chip_size;
+}
-void __init amiga_chip_init (void)
+
+void *amiga_chip_alloc(unsigned long size, const char *name)
{
- struct chip_desc *dp;
-
- if (!AMIGAHW_PRESENT(CHIP_RAM))
- return;
+ struct resource *res;
- chipram.end = amiga_chip_size-1;
- request_resource(&iomem_resource, &chipram);
-
- /* initialize start boundary */
-
- dp = DP(chipaddr);
- dp->first = 1;
-
- dp->alloced = 0;
- dp->length = amiga_chip_size - 2*sizeof(*dp);
-
- /* initialize end boundary */
- dp = DP(chipaddr + amiga_chip_size) - 1;
- dp->last = 1;
-
- dp->alloced = 0;
- dp->length = amiga_chip_size - 2*sizeof(*dp);
- chipavail = dp->length; /*MILAN*/
+ /* round up */
+ size = PAGE_ALIGN(size);
#ifdef DEBUG
- printk ("chipram end boundary is %p, length is %d\n", dp,
- dp->length);
+ printk("amiga_chip_alloc: allocate %ld bytes\n", size);
#endif
+ res = kmalloc(sizeof(struct resource), GFP_KERNEL);
+ if (!res)
+ return NULL;
+ memset(res, 0, sizeof(struct resource));
+ res->name = name;
+
+ if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) {
+ kfree(res);
+ return NULL;
+ }
+ chipavail -= size;
+#ifdef DEBUG
+ printk("amiga_chip_alloc: returning %lx\n", res->start);
+#endif
+ return (void *)ZTWO_VADDR(res->start);
}
-void *amiga_chip_alloc(long size, const char *name)
-{
- /* last chunk */
- struct chip_desc *dp;
- void *ptr;
- /* round off */
- size = (size + 7) & ~7;
+ /*
+ * Warning:
+ * amiga_chip_alloc_res is meant only for drivers that need to allocate
+ * Chip RAM before kmalloc() is functional. As a consequence, those
+ * drivers must not free that Chip RAM afterwards.
+ */
-#ifdef DEBUG
- printk("amiga_chip_alloc: allocate %ld bytes\n", size);
-#endif
+void * __init amiga_chip_alloc_res(unsigned long size, struct resource *res)
+{
+ unsigned long start;
+
+ /* round up */
+ size = PAGE_ALIGN(size);
+ /* dmesg into chipmem prefers memory at the safe end */
+ start = CHIP_PHYSADDR + chipavail - size;
- /*
- * get pointer to descriptor for last chunk by
- * going backwards from end chunk
- */
- dp = DP(chipaddr + amiga_chip_size) - 1;
- dp = DP((unsigned long)dp - dp->length) - 1;
-
- while ((dp->alloced || dp->length < size)
- && !dp->first)
- dp = DP ((unsigned long)dp - dp[-1].length) - 2;
-
- if (dp->alloced || dp->length < size) {
- printk ("no chipmem available for %ld allocation\n", size);
- return NULL;
- }
-
- if (dp->length < (size + 2*sizeof(*dp))) {
- /* length too small to split; allocate the whole thing */
- dp->alloced = 1;
- ptr = (void *)(dp+1);
- dp = DP((unsigned long)ptr + dp->length);
- dp->alloced = 1;
#ifdef DEBUG
- printk ("amiga_chip_alloc: no split\n");
+ printk("amiga_chip_alloc_res: allocate %ld bytes\n", size);
#endif
- } else {
- /* split the extent; use the end part */
- long newsize = dp->length - (2*sizeof(*dp) + size);
-
+ if (allocate_resource(&chipram_res, res, size, start, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) {
+ printk("amiga_chip_alloc_res: first alloc failed!\n");
+ if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0)
+ return NULL;
+ }
+ chipavail -= size;
#ifdef DEBUG
- printk ("amiga_chip_alloc: splitting %d to %ld\n", dp->length,
- newsize);
+ printk("amiga_chip_alloc_res: returning %lx\n", res->start);
#endif
- dp->length = newsize;
- dp = DP((unsigned long)(dp+1) + newsize);
- dp->first = dp->last = 0;
- dp->alloced = 0;
- dp->length = newsize;
- dp++;
- dp->first = dp->last = 0;
- dp->alloced = 1;
- dp->length = size;
- ptr = (void *)(dp+1);
- dp = DP((unsigned long)ptr + size);
- dp->alloced = 1;
- dp->length = size;
- }
+ return (void *)ZTWO_VADDR(res->start);
+}
+void amiga_chip_free(void *ptr)
+{
+ unsigned long start = ZTWO_PADDR(ptr);
+ struct resource **p, *res;
+ unsigned long size;
+
+ for (p = &chipram_res.child; (res = *p); p = &res->sibling) {
+ if (res->start != start)
+ continue;
+ *p = res->sibling;
+ size = res->end-start;
#ifdef DEBUG
- printk ("amiga_chip_alloc: returning %p\n", ptr);
+ printk("amiga_chip_free: free %ld bytes at %p\n", size, ptr);
#endif
-
- if ((unsigned long)ptr & 7)
- panic("amiga_chip_alloc: alignment violation\n");
-
- chipavail -= size + (2*sizeof(*dp)); /*MILAN*/
-
- if (!request_mem_region(ZTWO_PADDR(ptr), size, name))
- printk(KERN_WARNING "amiga_chip_alloc: region of size %ld at 0x%08lx "
- "is busy\n", size, ZTWO_PADDR(ptr));
-
- return ptr;
+ chipavail += size;
+ kfree(res);
+ return;
+ }
+ printk("amiga_chip_free: trying to free nonexistent region at %p\n", ptr);
}
-void amiga_chip_free (void *ptr)
-{
- struct chip_desc *sdp = DP(ptr) - 1, *dp2;
- struct chip_desc *edp = DP((unsigned long)ptr + sdp->length);
- chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/
+unsigned long amiga_chip_avail(void)
+{
#ifdef DEBUG
- printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr);
+ printk("amiga_chip_avail : %ld bytes\n", chipavail);
#endif
- /* deallocate the chunk */
- sdp->alloced = edp->alloced = 0;
- release_mem_region(ZTWO_PADDR(ptr), sdp->length);
-
- /* check if we should merge with the previous chunk */
- if (!sdp->first && !sdp[-1].alloced) {
- dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2;
- dp2->length += sdp->length + 2*sizeof(*sdp);
- edp->length = dp2->length;
- sdp = dp2;
- }
-
- /* check if we should merge with the following chunk */
- if (!edp->last && !edp[1].alloced) {
- dp2 = DP((unsigned long)edp + edp[1].length) + 2;
- dp2->length += edp->length + 2*sizeof(*sdp);
- sdp->length = dp2->length;
- edp = dp2;
- }
+ return chipavail;
}
u_short int_mask;
int handler_irq, cia_irq, server_irq;
char *name;
- struct irq_server server;
irq_handler_t irq_list[CIA_IRQS];
} ciaa_base = {
&ciaa, 0, 0, IF_PORTS,
IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA,
IRQ_AMIGA_PORTS,
- "CIAA handler", {0, 0}
+ "CIAA handler"
}, ciab_base = {
&ciab, 0, 0, IF_EXTER,
IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB,
IRQ_AMIGA_EXTER,
- "CIAB handler", {0, 0}
+ "CIAB handler"
};
/*
}
ints >>= 1;
}
- amiga_do_irq_list(base->server_irq, fp, &base->server);
+ amiga_do_irq_list(base->server_irq, fp);
}
void __init cia_init_IRQ(struct ciabase *base)
#include <asm/amigahw.h>
#include <asm/amigaints.h>
#include <asm/irq.h>
+#include <asm/keyboard.h>
#include <asm/machdep.h>
#include <asm/io.h>
/* amiga specific keyboard functions */
extern int amiga_keyb_init(void);
extern int amiga_kbdrate (struct kbd_repeat *);
+extern int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep,
+ char raw_mode);
/* amiga specific irq functions */
extern void amiga_init_IRQ (void);
extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *);
mach_sched_init = amiga_sched_init;
mach_keyb_init = amiga_keyb_init;
mach_kbdrate = amiga_kbdrate;
+ mach_kbd_translate = amiga_kbd_translate;
+ SYSRQ_KEY = 0xff;
mach_init_IRQ = amiga_init_IRQ;
mach_default_handler = &amiga_default_handler;
mach_request_irq = amiga_request_irq;
static void amiga_savekmsg_init(void)
{
- savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM, "Debug");
+ static struct resource debug_res = { "Debug" };
+
+ savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
savekmsg->magic1 = SAVEKMSG_MAGIC1;
savekmsg->magic2 = SAVEKMSG_MAGIC2;
savekmsg->magicptr = virt_to_phys(savekmsg);
#include <linux/random.h>
#include <linux/init.h>
#include <linux/kbd_ll.h>
+#include <linux/kbd_kern.h>
#include <asm/atariints.h>
#include <asm/atarihw.h>
if (acia_stat & ACIA_RDRF) /* received a character */
{
scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */
- mark_bh(KEYBOARD_BH);
+ tasklet_schedule(&keyboard_tasklet);
interpret_scancode:
switch (kb_state.state)
{
return( 0 );
}
+
+int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
+{
+#ifdef CONFIG_MAGIC_SYSRQ
+ /* ALT+HELP pressed? */
+ if ((keycode == 98) && ((shift_state & 0xff) == 8))
+ *keycodep = 0xff;
+ else
+#endif
+ *keycodep = keycode;
+ return 1;
+}
+
/* atari specific keyboard functions */
extern int atari_keyb_init(void);
extern int atari_kbdrate (struct kbd_repeat *);
+extern int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep,
+ char raw_mode);
extern void atari_kbd_leds (unsigned int);
/* atari specific irq functions */
extern void atari_init_IRQ (void);
mach_sched_init = atari_sched_init;
mach_keyb_init = atari_keyb_init;
mach_kbdrate = atari_kbdrate;
+ mach_kbd_translate = atari_kbd_translate;
+ SYSRQ_KEY = 0xff;
mach_kbd_leds = atari_kbd_leds;
mach_init_IRQ = atari_init_IRQ;
mach_request_irq = atari_request_irq;
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/shm.h>
+#include <linux/bootmem.h>
#include <asm/setup.h>
#include <asm/machdep.h>
#ifdef CONFIG_STRAM_SWAP
#define MAJOR_NR Z2RAM_MAJOR
+#define do_z2_request do_stram_request
#include <linux/blk.h>
#undef DEVICE_NAME
#define DEVICE_NAME "stram"
unswap_by_move disabled because it does not handle swapped shm pages.
*/
+/* 2000-05-01: ++andreas
+ Integrated with bootmem. Remove all traces of unswap_by_move.
+*/
+
#ifdef CONFIG_STRAM_SWAP
#define ALIGN_IF_SWAP(x) PAGE_ALIGN(x)
#else
#endif
/* get index of swap page at address 'addr' */
-#define SWAP_NR(addr) (((unsigned long)(addr)-swap_start) >> PAGE_SHIFT)
+#define SWAP_NR(addr) (((addr) - swap_start) >> PAGE_SHIFT)
/* get address of swap page #'nr' */
-#define SWAP_ADDR(nr) ((void *)(swap_start + ((nr)<<PAGE_SHIFT)))
+#define SWAP_ADDR(nr) (swap_start + ((nr) << PAGE_SHIFT))
/* get number of pages for 'n' bytes (already page-aligned) */
#define N_PAGES(n) ((n) >> PAGE_SHIFT)
#define MAX_STRAM_FRACTION_NOM 1
#define MAX_STRAM_FRACTION_DENOM 3
-/* Start and end of the (pre-mem_init) reserved ST-RAM region */
-static unsigned long rsvd_stram_beg, rsvd_stram_end;
-
/* Start and end (virtual) of ST-RAM */
-static unsigned long stram_start, stram_end;
+static void *stram_start, *stram_end;
/* set after memory_init() executed and allocations via start_mem aren't
* possible anymore */
typedef struct stram_block {
struct stram_block *next;
- unsigned long start;
+ void *start;
unsigned long size;
unsigned flags;
const char *owner;
/* values for flags field */
#define BLOCK_FREE 0x01 /* free structure in the BLOCKs pool */
#define BLOCK_KMALLOCED 0x02 /* structure allocated by kmalloc() */
-#define BLOCK_STATIC 0x04 /* pre-mem_init() allocated block */
#define BLOCK_GFP 0x08 /* block allocated with __get_dma_pages() */
#define BLOCK_INSWAP 0x10 /* block allocated in swap space */
static int max_swap_size = -1;
/* start and end of swapping area */
-static unsigned long swap_start, swap_end;
+static void *swap_start, *swap_end;
/* The ST-RAM's swap info structure */
static struct swap_info_struct *stram_swap_info;
#ifdef DO_PROC
static unsigned stat_swap_read = 0;
static unsigned stat_swap_write = 0;
-static unsigned stat_swap_move = 0;
static unsigned stat_swap_force = 0;
#endif /* DO_PROC */
/***************************** Prototypes *****************************/
#ifdef CONFIG_STRAM_SWAP
-static int swap_init( unsigned long start_mem, unsigned long swap_data );
+static int swap_init(void *start_mem, void *swap_data);
static void *get_stram_region( unsigned long n_pages );
static void free_stram_region( unsigned long offset, unsigned long n_pages
);
-static int in_some_region( unsigned long addr );
+static int in_some_region(void *addr);
static unsigned long find_free_region( unsigned long n_pages, unsigned long
*total_free, unsigned long
*region_free );
-static void do_stram_request( void );
+static void do_stram_request(request_queue_t *);
static int stram_open( struct inode *inode, struct file *filp );
static int stram_release( struct inode *inode, struct file *filp );
-static void do_z2_request( void );
#endif
-static int get_gfp_order( unsigned long size );
-static void reserve_region( unsigned long addr, unsigned long end );
+static void reserve_region(void *start, void *end);
static BLOCK *add_region( void *addr, unsigned long size );
static BLOCK *find_region( void *addr );
static int remove_region( BLOCK *block );
/* determine whether kernel code resides in ST-RAM (then ST-RAM is the
* first memory block at virtual 0x0) */
- stram_start = (unsigned long)phys_to_virt(0);
+ stram_start = phys_to_virt(0);
kernel_in_stram = (stram_start == 0);
for( i = 0; i < m68k_num_memory; ++i ) {
if (m68k_memory[i].addr == 0) {
/* skip first 2kB or page (supervisor-only!) */
- rsvd_stram_beg = stram_start + ALIGN_IF_SWAP(0x800);
- rsvd_stram_end = rsvd_stram_beg;
stram_end = stram_start + m68k_memory[i].size;
return;
}
/*
- * This function is called from mem_init() to reserve the pages needed for
+ * This function is called from setup_arch() to reserve the pages needed for
* ST-RAM management.
*/
-void __init atari_stram_reserve_pages(unsigned long start_mem)
+void __init atari_stram_reserve_pages(void *start_mem)
{
#ifdef CONFIG_STRAM_SWAP
/* if max_swap_size is negative (i.e. no stram_swap= option given),
max_swap_size =
(!MACH_IS_HADES &&
(N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <=
- max_mapnr*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0;
+ (high_memory>>PAGE_SHIFT)*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0;
DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size );
#endif
/* always reserve first page of ST-RAM, the first 2 kB are
* supervisor-only! */
- set_bit( PG_reserved, &virt_to_page(stram_start)->flags );
+ if (!kernel_in_stram)
+ reserve_bootmem (0, PAGE_SIZE);
#ifdef CONFIG_STRAM_SWAP
- if (!max_swap_size) {
- fallback:
-#endif
- DPRINTK( "atari_stram_reserve_pages: swapping disabled\n" );
- if (!kernel_in_stram) {
- /* Reserve all pages that have been marked by pre-mem_init
- * stram_alloc() (e.g. for the screen memory). */
- reserve_region( rsvd_stram_beg, rsvd_stram_end );
- DPRINTK( "atari_stram_reserve_pages: reseverved %08lx-%08lx\n",
- rsvd_stram_beg, rsvd_stram_end );
- }
- /* else (kernel in ST-RAM): nothing to do, ST-RAM buffers are
- * kernel data */
-#ifdef CONFIG_STRAM_SWAP
- }
- else {
- unsigned long swap_data;
- BLOCK *p;
-
- /* determine first page to use as swap:
- * if the kernel is in TT-RAM, this is the first page of (usable)
- * ST-RAM; else if there were already some allocations (probable...),
- * use the lowest address of these (the list is sorted by address!);
- * otherwise just use the end of kernel data (= start_mem) */
- swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE :
- alloc_list ? alloc_list->start :
- start_mem;
+ {
+ void *swap_data;
+
+ start_mem = (void *) PAGE_ALIGN ((unsigned long) start_mem);
+ /* determine first page to use as swap: if the kernel is
+ in TT-RAM, this is the first page of (usable) ST-RAM;
+ otherwise just use the end of kernel data (= start_mem) */
+ swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE : start_mem;
/* decrement by one page, rest of kernel assumes that first swap page
* is always reserved and maybe doesn't handle SWP_ENTRY == 0
* correctly */
if (swap_end-swap_start > max_swap_size)
swap_end = swap_start + max_swap_size;
DPRINTK( "atari_stram_reserve_pages: swapping enabled; "
- "swap=%08lx-%08lx\n", swap_start, swap_end );
+ "swap=%p-%p\n", swap_start, swap_end);
/* reserve some amount of memory for maintainance of
* swapping itself: one page for each 2048 (PAGE_SIZE/2)
start_mem += ((SWAP_NR(swap_end) + PAGE_SIZE/2 - 1)
>> (PAGE_SHIFT-1)) << PAGE_SHIFT;
/* correct swap_start if necessary */
- if (swap_start == swap_data)
- swap_start = start_mem;
+ if (swap_start + PAGE_SIZE == swap_data)
+ swap_start = start_mem - PAGE_SIZE;
if (!swap_init( start_mem, swap_data )) {
printk( KERN_ERR "ST-RAM swap space initialization failed\n" );
max_swap_size = 0;
- goto fallback;
+ return;
}
/* reserve region for swapping meta-data */
- reserve_region( swap_data, start_mem );
+ reserve_region(swap_data, start_mem);
/* reserve swapping area itself */
- reserve_region( swap_start+PAGE_SIZE, swap_end );
-
- /* Formerly static areas have been included in the swap area. */
- for( p = alloc_list; p; p = p->next ) {
- if (p->flags & BLOCK_STATIC)
- p->flags = (p->flags & ~BLOCK_STATIC) | BLOCK_INSWAP;
- }
+ reserve_region(swap_start + PAGE_SIZE, swap_end);
/*
* If the whole ST-RAM is used for swapping, there are no allocatable
* You just will get non-DMA-able memory...
*/
mach_max_dma_address = 0xffffffff;
-
- /*
- * Ok, num_physpages needs not be really exact, but it's better to
- * subtract the pages set aside for swapping.
- */
- num_physpages -= SWAP_NR(swap_end)-1;
}
#endif
-
+}
+
+void atari_stram_mem_init_hook (void)
+{
mem_init_done = 1;
}
* likely to fail :-(
*
*/
-void *atari_stram_alloc( long size, unsigned long *start_mem,
- const char *owner )
+void *atari_stram_alloc(long size, const char *owner)
{
void *addr = NULL;
BLOCK *block;
int flags;
- DPRINTK( "atari_stram_alloc(size=%08lx,*start_mem=%08lx,owner=%s)\n",
- size, start_mem ? *start_mem : 0xffffffff, owner );
-
- if (start_mem && mem_init_done) {
- printk( KERN_ERR "atari_stram_alloc called with start_mem!=NULL "
- "after mem_init() from %p\n", __builtin_return_address(0) );
- return( NULL );
- }
- if (!start_mem && !mem_init_done) {
- printk( KERN_ERR "atari_stram_alloc called with start_mem==NULL "
- "before mem_init() from %p\n", __builtin_return_address(0) );
- return( NULL );
- }
+ DPRINTK("atari_stram_alloc(size=%08lx,owner=%s)\n", size, owner);
size = ALIGN_IF_SWAP(size);
DPRINTK( "atari_stram_alloc: rounded size = %08lx\n", size );
- if (!mem_init_done) {
- /* before mem_init(): allocate "statically", i.e. either in the kernel
- * data space (current end in *start_mem), or at the end of currently
- * reserved ST-RAM. */
- if (kernel_in_stram) {
- /* Get memory from kernel data space */
- *start_mem = ALIGN_IF_SWAP(*start_mem);
- addr = (void *)*start_mem;
- *start_mem += size;
- DPRINTK( "atari_stram_alloc: pre-mem_init and k/ST: "
- "shifted start_mem to %08lx, addr=%p\n",
- *start_mem, addr );
- }
- else {
- /* Get memory from rsvd_stram_beg */
- if (rsvd_stram_end + size < stram_end) {
- addr = (void *) rsvd_stram_end;
- rsvd_stram_end += size;
- DPRINTK( "atari_stram_alloc: pre-mem_init and k/TT: "
- "shifted rsvd_stram_end to %08lx, addr=%p\n",
- rsvd_stram_end, addr );
- }
- }
- flags = BLOCK_STATIC;
- }
#ifdef CONFIG_STRAM_SWAP
- else if (max_swap_size) {
- /* If swapping is active (can only be the case after mem_init()!):
- * make some free space in the swap "device". */
+ if (max_swap_size) {
+ /* If swapping is active: make some free space in the swap
+ "device". */
DPRINTK( "atari_stram_alloc: after mem_init, swapping ok, "
"calling get_region\n" );
addr = get_stram_region( N_PAGES(size) );
flags = BLOCK_INSWAP;
}
+ else
#endif
+ if (!mem_init_done)
+ return alloc_bootmem_low(size);
else {
/* After mem_init() and no swapping: can only resort to
* __get_dma_pages() */
- addr = (void *)__get_dma_pages(GFP_KERNEL, get_gfp_order(size));
+ addr = (void *)__get_dma_pages(GFP_KERNEL, get_order(size));
flags = BLOCK_GFP;
DPRINTK( "atari_stram_alloc: after mem_init, swapping off, "
"get_pages=%p\n", addr );
/* out of memory for BLOCK structure :-( */
DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- "
"freeing again\n" );
- if (flags == BLOCK_STATIC)
- rsvd_stram_end -= size;
#ifdef CONFIG_STRAM_SWAP
- else if (flags == BLOCK_INSWAP)
+ if (flags == BLOCK_INSWAP)
free_stram_region( SWAP_NR(addr), N_PAGES(size) );
-#endif
else
- free_pages( (unsigned long)addr, get_gfp_order(size));
+#endif
+ free_pages((unsigned long)addr, get_order(size));
return( NULL );
}
block->owner = owner;
if (!max_swap_size) {
#endif
if (block->flags & BLOCK_GFP) {
- DPRINTK( "atari_stram_free: is kmalloced, order_size=%d\n",
- get_gfp_order(block->size) );
- free_pages( (unsigned long)addr, get_gfp_order(block->size) );
+ DPRINTK("atari_stram_free: is kmalloced, order_size=%d\n",
+ get_order(block->size));
+ free_pages((unsigned long)addr, get_order(block->size));
}
else
goto fail;
#ifdef CONFIG_STRAM_SWAP
}
- else if (block->flags & (BLOCK_INSWAP|BLOCK_STATIC)) {
+ else if (block->flags & BLOCK_INSWAP) {
DPRINTK( "atari_stram_free: is swap-alloced\n" );
free_stram_region( SWAP_NR(block->start), N_PAGES(block->size) );
}
* Initialize ST-RAM swap device
* (lots copied and modified from sys_swapon() in mm/swapfile.c)
*/
-static int __init swap_init(unsigned long start_mem, unsigned long swap_data)
+static int __init swap_init(void *start_mem, void *swap_data)
{
- static struct dentry fake_dentry[3];
+ static struct dentry fake_dentry;
+ static struct vfsmount fake_vfsmnt;
struct swap_info_struct *p;
struct inode swap_inode;
unsigned int type;
- unsigned long addr;
+ void *addr;
int i, j, k, prev;
- DPRINTK( "swap_init(start_mem=%08lx, swap_data=%08lx)\n",
- start_mem, swap_data );
+ DPRINTK("swap_init(start_mem=%p, swap_data=%p)\n",
+ start_mem, swap_data);
/* need at least one page for swapping to (and this also isn't very
* much... :-) */
stram_swap_type = type;
/* fake some dir cache entries to give us some name in /dev/swaps */
- fake_dentry[0].d_covers = &fake_dentry[1];
- fake_dentry[0].d_parent = &fake_dentry[0];
- fake_dentry[1].d_parent = &fake_dentry[2];
- fake_dentry[1].d_name.name = "stram (internal)";
- fake_dentry[1].d_name.len = 16;
- fake_dentry[2].d_covers = &fake_dentry[2];
- fake_dentry[2].d_parent = &fake_dentry[2];
+ fake_dentry.d_parent = &fake_dentry;
+ fake_dentry.d_name.name = "stram (internal)";
+ fake_dentry.d_name.len = 16;
+ fake_vfsmnt.mnt_parent = &fake_vfsmnt;
p->flags = SWP_USED;
- p->swap_file = &fake_dentry[0];
+ p->swap_file = &fake_dentry;
+ p->swap_vfsmnt = &fake_vfsmnt;
p->swap_device = 0;
- p->swap_map = (unsigned short *)swap_data;
+ p->swap_map = swap_data;
p->cluster_nr = 0;
p->next = -1;
p->prio = 0x7ff0; /* a rather high priority, but not the higest
k = 0; /* # of already allocated pages (from pre-mem_init stram_alloc()) */
p->lowest_bit = 0;
p->highest_bit = 0;
- for( i = 1, addr = (unsigned long)SWAP_ADDR(1); i < p->max;
+ for( i = 1, addr = SWAP_ADDR(1); i < p->max;
i++, addr += PAGE_SIZE ) {
if (in_some_region( addr )) {
p->swap_map[i] = SWAP_MAP_BAD;
* what to do if a write is requested later.
*/
static inline void unswap_pte(struct vm_area_struct * vma, unsigned long
- address, pte_t *dir, unsigned long entry,
- unsigned long page /*, int isswap */)
+ address, pte_t *dir, swp_entry_t entry,
+ struct page *page)
{
pte_t pte = *dir;
memory */
if (pte_page(pte) != page)
return;
- if (0 /* isswap */)
- virt_to_page(pte_page(pte))->offset = page;
- else
- /* We will be removing the swap cache in a moment, so... */
- set_pte(dir, pte_mkdirty(pte));
+ /* We will be removing the swap cache in a moment, so... */
+ set_pte(dir, pte_mkdirty(pte));
return;
}
- if (pte_val(pte) != entry)
+ if (pte_val(pte) != entry.val)
return;
- if (0 /* isswap */) {
- DPRINTK( "unswap_pte: replacing entry %08lx by %08lx", entry, page );
- set_pte(dir, __pte(page));
- }
- else {
- DPRINTK( "unswap_pte: replacing entry %08lx by new page %08lx",
- entry, page );
- set_pte(dir, pte_mkdirty(__mk_pte(page,vma->vm_page_prot)));
- atomic_inc(&virt_to_page(page)->count);
- ++vma->vm_mm->rss;
- }
+ DPRINTK("unswap_pte: replacing entry %08lx by new page %p",
+ entry.val, page);
+ set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
swap_free(entry);
+ get_page(page);
+ ++vma->vm_mm->rss;
}
static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir,
unsigned long address, unsigned long size,
- unsigned long offset, unsigned long entry,
- unsigned long page /* , int isswap */)
+ unsigned long offset, swp_entry_t entry,
+ struct page *page)
{
pte_t * pte;
unsigned long end;
if (pmd_none(*dir))
return;
if (pmd_bad(*dir)) {
- printk("unswap_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
+ pmd_ERROR(*dir);
pmd_clear(dir);
return;
}
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
- unswap_pte(vma, offset+address-vma->vm_start, pte, entry,
- page /* , isswap */);
+ unswap_pte(vma, offset+address-vma->vm_start, pte, entry, page);
address += PAGE_SIZE;
pte++;
} while (address < end);
static inline void unswap_pgd(struct vm_area_struct * vma, pgd_t *dir,
unsigned long address, unsigned long size,
- unsigned long entry, unsigned long page
- /* , int isswap */)
+ swp_entry_t entry, struct page *page)
{
pmd_t * pmd;
unsigned long offset, end;
if (pgd_none(*dir))
return;
if (pgd_bad(*dir)) {
- printk("unswap_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
+ pgd_ERROR(*dir);
pgd_clear(dir);
return;
}
end = PGDIR_SIZE;
do {
unswap_pmd(vma, pmd, address, end - address, offset, entry,
- page /* , isswap */);
+ page);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
}
static void unswap_vma(struct vm_area_struct * vma, pgd_t *pgdir,
- unsigned long entry, unsigned long page
- /* , int isswap */)
+ swp_entry_t entry, struct page *page)
{
unsigned long start = vma->vm_start, end = vma->vm_end;
- while (start < end) {
- unswap_pgd(vma, pgdir, start, end - start, entry, page
- /* , isswap */);
+ do {
+ unswap_pgd(vma, pgdir, start, end - start, entry, page);
start = (start + PGDIR_SIZE) & PGDIR_MASK;
pgdir++;
- }
+ } while (start < end);
}
-static void unswap_process(struct mm_struct * mm, unsigned long entry,
- unsigned long page /* , int isswap */)
+static void unswap_process(struct mm_struct * mm, swp_entry_t entry,
+ struct page *page)
{
struct vm_area_struct* vma;
return;
for (vma = mm->mmap; vma; vma = vma->vm_next) {
pgd_t * pgd = pgd_offset(mm, vma->vm_start);
- unswap_vma(vma, pgd, entry, page /* , isswap */);
+ unswap_vma(vma, pgd, entry, page);
}
}
-#if 0
-static int unswap_by_move(unsigned short *map, unsigned long max,
- unsigned long start, unsigned long n_pages)
-{
- struct task_struct *p;
- unsigned long entry, rover = (start == 1) ? n_pages+1 : 1;
- unsigned long i, j;
-
- DPRINTK( "unswapping %lu..%lu by moving in swap\n",
- start, start+n_pages-1 );
-
- /* can free the allocated pages by moving them to other swap pages */
- for( i = start; i < start+n_pages; ++i ) {
- if (!map[i]) {
- map[i] = SWAP_MAP_BAD;
- DPRINTK( "unswap: page %lu was free\n", i );
- continue;
- }
- else if (map[i] == SWAP_MAP_BAD) {
- printk( KERN_ERR "get_stram_region: page %lu already "
- "reserved??\n", i );
- }
- DPRINTK( "unswap: page %lu is alloced, count=%u\n", i, map[i] );
-
- /* find a free page not in our region */
- for( j = rover; j != rover-1; j = (j == max-1) ? 1 : j+1 ) {
- if (j >= start && j < start+n_pages)
- continue;
- if (!map[j]) {
- rover = j+1;
- break;
- }
- }
- if (j == rover-1) {
- printk( KERN_ERR "get_stram_region: not enough free swap "
- "pages now??\n" );
- return( -ENOMEM );
- }
- DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n",
- i, map[i], j, map[j], nr_swap_pages );
-
- --nr_swap_pages;
- entry = SWP_ENTRY( stram_swap_type, j );
- if (stram_swap_info->lowest_bit == j)
- stram_swap_info->lowest_bit++;
- if (stram_swap_info->highest_bit == j)
- stram_swap_info->highest_bit--;
-
- memcpy( SWAP_ADDR(j), SWAP_ADDR(i), PAGE_SIZE );
-#ifdef DO_PROC
- stat_swap_move++;
-#endif
-
- while( map[i] ) {
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (unswap_process( p->mm, SWP_ENTRY( stram_swap_type, i ),
- entry, 1 )) {
- read_unlock(&tasklist_lock);
- map[j]++;
- goto repeat;
- }
- }
- read_unlock(&tasklist_lock);
- if (map[i] && map[i] != SWAP_MAP_MAX) {
- printk( KERN_ERR "get_stram_region: ST-RAM swap page %lu "
- "not used by any process\n", i );
- /* quit while loop and overwrite bad map entry */
- break;
- }
- else if (!map[i]) {
- /* somebody else must have swapped in that page, so free the
- * new one (we're moving to) */
- DPRINTK( "unswap: map[i] became 0, also clearing map[j]\n" );
- map[j] = 0;
- }
- repeat:
- }
-
- DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n",
- i, map[i], j, map[j], nr_swap_pages );
- map[i] = SWAP_MAP_BAD;
- if (stram_swap_info->lowest_bit == i)
- stram_swap_info->lowest_bit++;
- if (stram_swap_info->highest_bit == i)
- stram_swap_info->highest_bit--;
- --nr_swap_pages;
- }
- return( 0 );
-}
-#endif
-
static int unswap_by_read(unsigned short *map, unsigned long max,
unsigned long start, unsigned long n_pages)
{
struct task_struct *p;
- unsigned long entry, page;
+ struct page *page;
+ swp_entry_t entry;
unsigned long i;
- struct page *page_map;
DPRINTK( "unswapping %lu..%lu by reading in\n",
start, start+n_pages-1 );
/* Get a page for the entry, using the existing
swap cache page if there is one. Otherwise,
get a clean page and read the swap into it. */
- page_map = read_swap_cache(entry);
- if (page_map) {
- page = (unsigned long) page_address(page_map);
- read_lock(&tasklist_lock);
- for_each_task(p)
- unswap_process(p->mm, entry, page
- /* , 0 */);
- read_unlock(&tasklist_lock);
- shm_unuse(entry, page);
- /* Now get rid of the extra reference to
- the temporary page we've been using. */
- if (PageSwapCache(page_map))
- delete_from_swap_cache(page_map);
- __free_page(page_map);
- #ifdef DO_PROC
- stat_swap_force++;
- #endif
- }
- else {
+ page = read_swap_cache(entry);
+ if (!page) {
swap_free(entry);
return -ENOMEM;
}
+ read_lock(&tasklist_lock);
+ for_each_task(p)
+ unswap_process(p->mm, entry, page);
+ read_unlock(&tasklist_lock);
+ shm_unuse(entry, page);
+ /* Now get rid of the extra reference to the
+ temporary page we've been using. */
+ if (PageSwapCache(page))
+ delete_from_swap_cache(page);
+ __free_page(page);
+ #ifdef DO_PROC
+ stat_swap_force++;
+ #endif
}
DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n",
DPRINTK( "get_stram_region: region starts at %lu, has %lu free pages\n",
start, region_free );
-#if 0
- err = ((total_free-region_free >= n_pages-region_free) ?
- unswap_by_move( map, max, start, n_pages ) :
- unswap_by_read( map, max, start, n_pages ));
-#else
err = unswap_by_read(map, max, start, n_pages);
-#endif
-
if (err)
goto end;
/* is addr in some of the allocated regions? */
-static int in_some_region( unsigned long addr )
+static int in_some_region(void *addr)
{
BLOCK *p;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static int refcnt = 0;
-static void do_stram_request( void )
+static void do_stram_request(request_queue_t *q)
{
- unsigned long start, len;
-
- while( !QUEUE_EMPTY ) {
- if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
- panic("stram: request list destroyed");
- if (CURRENT->bh) {
- if (!buffer_locked(CURRENT->bh))
- panic("stram: block not locked");
- }
+ void *start;
+ unsigned long len;
+
+ while (1) {
+ INIT_REQUEST;
start = swap_start + (CURRENT->sector << 9);
len = CURRENT->current_nr_sectors << 9;
}
if (CURRENT->cmd == READ) {
- memcpy( CURRENT->buffer, (char *)start, len );
+ memcpy(CURRENT->buffer, start, len);
#ifdef DO_PROC
stat_swap_read += N_PAGES(len);
#endif
}
else {
- memcpy( (char *)start, CURRENT->buffer, len );
+ memcpy(start, CURRENT->buffer, len);
#ifdef DO_PROC
stat_swap_write += N_PAGES(len);
#endif
return( -ENXIO );
}
- blk_dev[STRAM_MAJOR].request_fn = do_stram_request;
+ blk_init_queue(BLK_DEFAULT_QUEUE(STRAM_MAJOR), do_stram_request);
blksize_size[STRAM_MAJOR] = stram_blocksizes;
stram_sizes[STRAM_MINOR] = (swap_end - swap_start)/1024;
blk_size[STRAM_MAJOR] = stram_sizes;
register_disk(NULL, MKDEV(STRAM_MAJOR, STRAM_MINOR), 1, &stram_fops,
(swap_end-swap_start)>>9);
- do_z2_request(); /* to avoid warning */
return( 0 );
}
-/* to avoid warning */
-static void do_z2_request( void ) { }
-
#endif /* CONFIG_STRAM_SWAP */
\f
/* Misc Utility Functions */
/* ------------------------------------------------------------------------ */
-
-/* return log2 of #pages for size */
-static int get_gfp_order( unsigned long size )
+/* reserve a range of pages */
+static void reserve_region(void *start, void *end)
{
- int order;
-
- size = N_PAGES( size + PAGE_SIZE -1 );
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
-
- return( order );
-}
-
-
-/* reserve a range of pages in mem_map[] */
-static void reserve_region( unsigned long addr, unsigned long end )
-{
- mem_map_t *mapp = virt_to_page(addr);
-
- for( ; addr < end; addr += PAGE_SIZE, ++mapp )
- set_bit( PG_reserved, &mapp->flags );
+ reserve_bootmem (virt_to_phys(start), end - start);
}
printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" );
return( NULL );
}
- n->start = (unsigned long)addr;
+ n->start = addr;
n->size = size;
for( p = &alloc_list; *p; p = &((*p)->next) )
- if ((*p)->start > (unsigned long)addr) break;
+ if ((*p)->start > addr) break;
n->next = *p;
*p = n;
BLOCK *p;
for( p = alloc_list; p; p = p->next ) {
- if (p->start == (unsigned long)addr)
+ if (p->start == addr)
return( p );
- if (p->start > (unsigned long)addr)
+ if (p->start > addr)
break;
}
return( NULL );
++used;
}
PRINT_PROC(
- "Total ST-RAM: %8lu kB\n"
+ "Total ST-RAM: %8u kB\n"
"Total ST-RAM swap: %8lu kB\n"
"Free swap: %8u kB\n"
"Used swap: %8u kB\n"
"Allocated swap: %8u kB\n"
"Swap Reads: %8u\n"
"Swap Writes: %8u\n"
- "Swap Moves: %8u\n"
"Swap Forced Reads: %8u\n",
(stram_end - stram_start) >> 10,
(max-1) << (PAGE_SHIFT-10),
rsvd << (PAGE_SHIFT-10),
stat_swap_read,
stat_swap_write,
- stat_swap_move,
stat_swap_force );
}
else {
#endif
PRINT_PROC( "ST-RAM swapping disabled\n" );
- PRINT_PROC(
- "Total ST-RAM: %8lu kB\n"
- "Reserved ST-RAM: %8lu kB\n",
- (stram_end - stram_start) >> 10,
- (rsvd_stram_end - rsvd_stram_beg) >> 10 );
+ PRINT_PROC("Total ST-RAM: %8u kB\n",
+ (stram_end - stram_start) >> 10);
#ifdef CONFIG_STRAM_SWAP
}
#endif
if (len + 50 >= PAGE_SIZE)
break;
PRINT_PROC("0x%08lx-0x%08lx: %s (",
- virt_to_phys((void *)p->start),
- virt_to_phys((void *)p->start+p->size-1),
+ virt_to_phys(p->start),
+ virt_to_phys(p->start+p->size-1),
p->owner);
- if (p->flags & BLOCK_STATIC)
- PRINT_PROC( "static)\n" );
- else if (p->flags & BLOCK_GFP)
+ if (p->flags & BLOCK_GFP)
PRINT_PROC( "page-alloced)\n" );
else if (p->flags & BLOCK_INSWAP)
PRINT_PROC( "in swap)\n" );
| save top of frame
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
- btst #PF_TRACESYS_BIT,%curptr@(TASK_FLAGS+PF_TRACESYS_OFF)
+ btst #PT_TRACESYS_BIT,%curptr@(TASK_PTRACE+PT_TRACESYS_OFF)
jne do_trace
cmpl #NR_syscalls,%d0
jcc badsys
jeq 2f
#endif
| check for delayed trace
- bclr #PF_DTRACE_BIT,%curptr@(TASK_FLAGS+PF_DTRACE_OFF)
+ bclr #PT_DTRACE_BIT,%curptr@(TASK_PTRACE+PT_DTRACE_OFF)
jne do_delayed_trace
5:
tstl %curptr@(TASK_STATE) | state
/* offsets into the task struct */
DEFINE(TASK_STATE, offsetof(struct task_struct, state));
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+ DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, sigpending));
DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, need_resched));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
ret = -EPERM;
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
- if (current->flags & PF_PTRACED)
+ if (current->ptrace & PT_PTRACED)
goto out;
/* set the ptrace bit in the process flags. */
- current->flags |= PF_PTRACED;
+ current->ptrace |= PT_PTRACED;
ret = 0;
goto out;
}
(current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
goto out;
/* the same process cannot be attached many times */
- if (child->flags & PF_PTRACED)
+ if (child->ptrace & PT_PTRACED)
goto out;
- child->flags |= PF_PTRACED;
+ child->ptrace |= PT_PTRACED;
write_lock_irqsave(&tasklist_lock, flags);
if (child->p_pptr != current) {
goto out;
}
ret = -ESRCH;
- if (!(child->flags & PF_PTRACED))
+ if (!(child->ptrace & PT_PTRACED))
goto out;
if (child->state != TASK_STOPPED) {
if (request != PTRACE_KILL)
if ((unsigned long) data > _NSIG)
goto out;
if (request == PTRACE_SYSCALL)
- child->flags |= PF_TRACESYS;
+ child->ptrace |= PT_TRACESYS;
else
- child->flags &= ~PF_TRACESYS;
+ child->ptrace &= ~PT_TRACESYS;
child->exit_code = data;
/* make sure the single step bit is not set. */
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
ret = -EIO;
if ((unsigned long) data > _NSIG)
goto out;
- child->flags &= ~PF_TRACESYS;
+ child->ptrace &= ~PT_TRACESYS;
tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
put_reg(child, PT_SR, tmp);
ret = -EIO;
if ((unsigned long) data > _NSIG)
goto out;
- child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
child->exit_code = data;
write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
asmlinkage void syscall_trace(void)
{
lock_kernel();
- if ((current->flags & (PF_PTRACED|PF_TRACESYS))
- != (PF_PTRACED|PF_TRACESYS))
+ if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
+ != (PT_PTRACED|PT_TRACESYS))
goto out;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
int (*mach_keyb_init) (void) __initdata = NULL;
int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
void (*mach_kbd_leds) (unsigned int) = NULL;
+int (*mach_kbd_translate)(unsigned char scancode, unsigned char *keycode, char raw_mode) = NULL;
+unsigned int SYSRQ_KEY;
/* machine dependent irq functions */
void (*mach_init_IRQ) (void) __initdata = NULL;
void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
if (!signr)
break;
- if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
regs->sr &= ~PS_T;
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/traps.h>
-#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
#include <asm/machdep.h>
#include <asm/siginfo.h>
if (fp->ptregs.sr & PS_S) {
if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
/* traced a trapping instruction */
- current->flags |= PF_DTRACE;
+ current->ptrace |= PT_DTRACE;
} else
bad_super_trap(fp);
return;
/* The phys. video addr. - might be bogus on some machines */
unsigned long mac_orig_videoaddr;
-/* Mac specific keyboard functions */
-extern int mackbd_init_hw(void);
-extern void mackbd_leds(unsigned int leds);
-
/* Mac specific timer functions */
extern void mac_gettod (int *, int *, int *, int *, int *, int *);
extern unsigned long mac_gettimeoffset (void);
extern void mac_debug_init(void);
extern void mac_debugging_long(int, long);
-#ifdef CONFIG_MAGIC_SYSRQ
-static char mac_sysrq_xlate[128] =
- "\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */
- "yt123465=97-80)o" /* 0x10 - 0x1f */
- "u(ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
- "\t `\000\033\000\000\000\000\000\000\000\000\000\000\000" /* 0x30 - 0x3f */
- "\000.\000*\000+\000\000\000\000\000/\r\000-\000" /* 0x40 - 0x4f */
- "\000\00001234567a89\000\000\000" /* 0x50 - 0x5f */
- "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x60 - 0x6f */
- "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */
-#endif
-
extern void (*kd_mksound)(unsigned int, unsigned int);
+extern int mackbd_init_hw(void);
+extern void mackbd_leds(unsigned int leds);
+extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode);
+
+extern void mac_hid_init_hw(void);
+extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+extern unsigned char mac_hid_kbd_sysrq_xlate[128];
+extern unsigned char pckbd_sysrq_xlate[128];
+extern unsigned char mackbd_sysrq_xlate[128];
+#endif /* CONFIG_MAGIC_SYSRQ */
+
static void mac_get_model(char *str);
void mac_bang(int irq, void *vector, struct pt_regs *p)
void __init config_mac(void)
{
-
- if (!MACH_IS_MAC) {
- printk("ERROR: no Mac, but config_mac() called!! \n");
- }
-
- mach_sched_init = mac_sched_init;
- mach_keyb_init = mackbd_init_hw;
- mach_kbd_leds = mackbd_leds;
- mach_init_IRQ = mac_init_IRQ;
- mach_request_irq = mac_request_irq;
- mach_free_irq = mac_free_irq;
- enable_irq = mac_enable_irq;
- disable_irq = mac_disable_irq;
- mach_get_model = mac_get_model;
- mach_default_handler = &mac_handlers;
- mach_get_irq_list = mac_get_irq_list;
- mach_gettimeoffset = mac_gettimeoffset;
- mach_gettod = mac_gettod;
- mach_hwclk = mac_hwclk;
- mach_set_clock_mmss = mac_set_clock_mmss;
+ if (!MACH_IS_MAC) {
+ printk("ERROR: no Mac, but config_mac() called!! \n");
+ }
+
+#ifdef CONFIG_VT
+#ifdef CONFIG_INPUT_ADBHID
+ mach_keyb_init = mac_hid_init_hw;
+ mach_kbd_translate = mac_hid_kbd_translate;
+#ifdef CONFIG_MAGIC_SYSRQ
+#ifdef CONFIG_MAC_ADBKEYCODES
+ if (!keyboard_sends_linux_keycodes) {
+ mach_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
+ SYSRQ_KEY = 0x69;
+ } else
+#endif /* CONFIG_MAC_ADBKEYCODES */
+ {
+ mach_sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
+ }
+#endif /* CONFIG_MAGIC_SYSRQ */
+#elif defined(CONFIG_ADB_KEYBOARD)
+ mach_keyb_init = mackbd_init_hw;
+ mach_kbd_leds = mackbd_leds;
+ mach_kbd_translate = mackbd_translate;
+ mach_sysrq_xlate = mackbd_sysrq_xlate;
+ SYSRQ_KEY = 0x69;
+#endif /* CONFIG_INPUT_ADBHID */
+#endif /* CONFIG_VT */
+
+ mach_sched_init = mac_sched_init;
+ mach_init_IRQ = mac_init_IRQ;
+ mach_request_irq = mac_request_irq;
+ mach_free_irq = mac_free_irq;
+ enable_irq = mac_enable_irq;
+ disable_irq = mac_disable_irq;
+ mach_get_model = mac_get_model;
+ mach_default_handler = &mac_handlers;
+ mach_get_irq_list = mac_get_irq_list;
+ mach_gettimeoffset = mac_gettimeoffset;
+ mach_gettod = mac_gettod;
+ mach_hwclk = mac_hwclk;
+ mach_set_clock_mmss = mac_set_clock_mmss;
#if 0
- mach_mksound = mac_mksound;
+ mach_mksound = mac_mksound;
#endif
- mach_reset = mac_reset;
- mach_halt = mac_poweroff;
- mach_power_off = mac_poweroff;
- conswitchp = &dummy_con;
- mach_max_dma_address = 0xffffffff;
+ mach_reset = mac_reset;
+ mach_halt = mac_poweroff;
+ mach_power_off = mac_poweroff;
+ conswitchp = &dummy_con;
+ mach_max_dma_address = 0xffffffff;
#if 0
- mach_debug_init = mac_debug_init;
-#endif
- kd_mksound = mac_mksound;
-#ifdef CONFIG_MAGIC_SYSRQ
- mach_sysrq_key = 114; /* HELP */
- mach_sysrq_shift_state = 8; /* Alt */
- mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */
- mach_sysrq_xlate = mac_sysrq_xlate;
+ mach_debug_init = mac_debug_init;
#endif
+ kd_mksound = mac_mksound;
#ifdef CONFIG_HEARTBEAT
#if 0
- mach_heartbeat = mac_heartbeat;
- mach_heartbeat_irq = IRQ_MAC_TIMER;
+ mach_heartbeat = mac_heartbeat;
+ mach_heartbeat_irq = IRQ_MAC_TIMER;
#endif
#endif
- /*
- * Determine hardware present
- */
+ /*
+ * Determine hardware present
+ */
- mac_identify();
- mac_report_hardware();
+ mac_identify();
+ mac_report_hardware();
- /* AFAIK only the IIci takes a cache card. The IIfx has onboard
- cache ... someone needs to figure out how to tell if it's on or
- not. */
- if (macintosh_config->ident == MAC_MODEL_IICI
- || macintosh_config->ident == MAC_MODEL_IIFX) {
- mach_l2_flush = mac_cache_card_flush;
- }
+ /* AFAIK only the IIci takes a cache card. The IIfx has onboard
+ cache ... someone needs to figure out how to tell if it's on or
+ not. */
+
+ if (macintosh_config->ident == MAC_MODEL_IICI
+ || macintosh_config->ident == MAC_MODEL_IIFX) {
+ mach_l2_flush = mac_cache_card_flush;
+ }
#ifdef MAC_DEBUG_SOUND
- /* goes on forever if timers broken */
- mac_mksound(1000,10);
+ /* goes on forever if timers broken */
+ mac_mksound(1000,10);
#endif
- /*
- * Check for machine specific fixups.
- */
+ /*
+ * Check for machine specific fixups.
+ */
#ifdef OLD_NUBUS_CODE
- nubus_sweep_video();
+ nubus_sweep_video();
#endif
}
extern char *q40_mem_cptr; /*=(char *)0xff020000;*/
static int _cpleft;
+int q40_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
+{
+ *keycodep = keycode;
+ return 1;
+}
+
static void q40_mem_console_write(struct console *co, const char *s,
unsigned int count)
{
mach_sched_init = q40_sched_init; /* ok */
/*mach_kbdrate = q40_kbdrate;*/ /* unneeded ?*/
mach_keyb_init = q40_keyb_init; /* OK */
+ mach_kbd_translate = q40_kbd_translate;
mach_init_IRQ = q40_init_IRQ;
mach_gettimeoffset = q40_gettimeoffset;
mach_gettod = q40_gettod;
pci_scan_bus(0, &nile4_pci_ops, NULL);
ddb5074_pci_fixup();
pci_assign_unassigned_resources();
- pci_set_bus_ranges();
pcibios_fixup_irqs();
}
static void amiga_savekmsg_init(void)
{
- savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM);
+ savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM, "Debug");
savekmsg->magic1 = SAVEKMSG_MAGIC1;
savekmsg->magic2 = SAVEKMSG_MAGIC2;
savekmsg->magicptr = virt_to_phys(savekmsg);
return -EBUSY;
}
if (!(acsi_buffer =
- (char *)atari_stram_alloc( ACSI_BUFFER_SIZE, NULL, "acsi" ))) {
+ (char *)atari_stram_alloc(ACSI_BUFFER_SIZE, "acsi"))) {
printk( KERN_ERR "Unable to get ACSI ST-Ram buffer.\n" );
devfs_unregister_blkdev( MAJOR_NR, "ad" );
return -ENOMEM;
SelectedDrive = -1;
BufferDrive = -1;
- DMABuffer = atari_stram_alloc( BUFFER_SIZE+512, NULL, "ataflop" );
+ DMABuffer = atari_stram_alloc(BUFFER_SIZE+512, "ataflop");
if (!DMABuffer) {
printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n");
unregister_blkdev(MAJOR_NR, "fd");
* Amiga support by Hamish Macdonald
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/random.h>
#include <linux/kernel.h>
+#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/kbd_kern.h>
kbd_pt_regs = NULL;
- init_timer(&amikeyb_rep_timer);
amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
add_timer(&amikeyb_rep_timer);
handle_scancode(rep_scancode, 1);
} else {
del_timer(&amikeyb_rep_timer);
rep_scancode = keycode;
- init_timer(&amikeyb_rep_timer);
amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
add_timer(&amikeyb_rep_timer);
}
{
if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
return -EIO;
+ if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
+ return -EBUSY;
/* setup key map */
memcpy(key_maps[0], amiplain_map, sizeof(plain_map));
return( 0 );
}
+
+int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
+{
+#ifdef CONFIG_MAGIC_SYSRQ
+ /* SHIFT+ALTGR+HELP pressed? */
+ if ((keycode == 0x5f) && ((shift_state & 0xff) == 3))
+ *keycodep = 0xff;
+ else
+#endif
+ *keycodep = keycode;
+ return 1;
+}
+
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/mm.h>
+#include <linux/keyboard.h>
#include <linux/signal.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/kbd_ll.h>
+#include <linux/kbd_kern.h>
#include <linux/delay.h>
#include <linux/sysrq.h>
#include <linux/random.h>
{
unsigned char status;
- disable_keyboard();
spin_lock(&kbd_controller_lock);
kbd_pt_regs = regs;
handle_scancode(scancode, ! keyup );
keyup=0;
- mark_bh(KEYBOARD_BH);
-
+ tasklet_schedule(&keyboard_tasklet);
}
else
keyup=1;
exit:
spin_unlock(&kbd_controller_lock);
master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */
- enable_keyboard();
-}
-
-
-
-
-#ifdef CONFIG_MAGIC_SYSRQ
-int kbd_is_sysrq(unsigned char keycode)
-{
- return( keycode == SYSRQ_KEY );
}
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-
#define KBD_NO_DATA (-1) /* No data */
if (dev->vendor == PCI_VENDOR_ID_PANACOM)
irq_config = 0x43;
if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
- (dev->device == PCI_VENDOR_ID_PLX_ROMULUS)) {
+ (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) {
/*
* As the megawolf cards have the int pins active
* high, and have 2 UART chips, both ints must be
SPCI_FL_BASE2, 8, 460800 },
/* Megawolf Romulus PCI Serial Card, from Mike Hudson */
/* (Exoray@isys.ca) */
- { PCI_VENDOR_ID_PLX, PCI_VENDOR_ID_PLX_ROMULUS,
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
0x10b5, 0x106a,
SPCI_FL_BASE2, 4, 921600,
0x20, 2, pci_plx9050_fn, 0x03 },
#define BUDDHA_BASE2 0xa00
#define BUDDHA_BASE3 0xc00
-static const u_int __init buddha_bases[CATWEASEL_NUM_HWIFS] = {
+static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
};
#define BUDDHA_STATUS 0x1e /* see status-bits */
#define BUDDHA_CONTROL 0x11a
-static int __init buddha_offsets[IDE_NR_PORTS] = {
+static int buddha_offsets[IDE_NR_PORTS] __initdata = {
BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL
};
#define BUDDHA_IRQ2 0xf40 /* interrupt */
#define BUDDHA_IRQ3 0xf80
-static const int __init buddha_irqports[CATWEASEL_NUM_HWIFS] = {
+static const int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
};
#include <linux/ide.h>
#include <linux/init.h>
+#include <asm/setup.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
+#include <asm/amigayle.h>
/*
#define GAYLE_STATUS 0x1e /* see status-bits */
#define GAYLE_CONTROL 0x101a
-static int __init gayle_offsets[IDE_NR_PORTS] = {
+static int gayle_offsets[IDE_NR_PORTS] __initdata = {
GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
};
unsigned char ch;
ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
- if (!(ch & 0x80))
+ if (!(ch & GAYLE_IRQ_IDE))
return 0;
return 1;
}
unsigned char ch;
ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
- if (!(ch & 0x80))
+ if (!(ch & GAYLE_IRQ_IDE))
return 0;
(void)inb(hwif->io_ports[IDE_STATUS_OFFSET]);
- outb(0x7c | (ch & 0x03), hwif->io_ports[IDE_IRQ_OFFSET]);
+ outb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
return 1;
}
macide_init();
}
#endif /* CONFIG_BLK_DEV_MAC_IDE */
+#ifdef CONFIG_BLK_DEV_Q40IDE
+ {
+ extern void q40ide_init(void);
+ q40ide_init();
+ }
+#endif /* CONFIG_BLK_DEV_Q40IDE */
#ifdef CONFIG_BLK_DEV_BUDDHA
{
extern void buddha_init(void);
/*
* linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver
*
- * original file created 12 Jul 1997 by Geert Uytterhoeven
+ * (c) Richard Zidlicky
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
- * RZ:
- * almost identical with pcide.c, maybe we can merge it later.
- * Differences:
- * max 2 HWIFS for now
- * translate portaddresses to q40 native addresses (not yet...) instead rely on in/out[bw]
- * address translation
*
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
* Bases of the IDE interfaces
*/
-#define PCIDE_NUM_HWIFS 2
+#define Q40IDE_NUM_HWIFS 2
#define PCIDE_BASE1 0x1f0
#define PCIDE_BASE2 0x170
#define PCIDE_BASE5 0x1e0
#define PCIDE_BASE6 0x160
-static const q40ide_ioreg_t pcide_bases[PCIDE_NUM_HWIFS] = {
+static const q40ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5,
PCIDE_BASE6 */
};
PCIDE_REG(CMD)
};
-int q40ide_default_irq(q40ide_ioreg_t base)
+static int q40ide_default_irq(q40ide_ioreg_t base)
{
switch (base) {
case 0x1f0: return 14;
}
}
-void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq)
-{
- q40ide_ioreg_t port = base;
- int i = 8;
-
- while (i--)
- *p++ = port++;
- *p++ = base + 0x206;
- if (irq != NULL)
- *irq = 0;
-}
/*
- * Probe for PC IDE interfaces
+ * Probe for Q40 IDE interfaces
*/
-int q40ide_probe_hwif(int index, ide_hwif_t *hwif)
+void q40ide_init(void)
{
- static int pcide_index[PCIDE_NUM_HWIFS] = { 0, };
int i;
if (!MACH_IS_Q40)
- return 0;
-
- for (i = 0; i < PCIDE_NUM_HWIFS; i++) {
- if (!pcide_index[i]) {
- /*printk("ide%d: Q40 IDE interface\n", index);*/
- pcide_index[i] = index+1;
- }
- if (pcide_index[i] == index+1) {
- ide_setup_ports(hwif,(ide_ioreg_t) pcide_bases[i], pcide_offsets, 0, /*q40_ack_intr???*/ NULL);
- hwif->irq = ide_default_irq((ide_ioreg_t)pcide_bases[i]); /*q40_ide_irq[i]; */ /* 14 */
- return 1;
- }
+ return ;
+
+ for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
+ hw_regs_t hw;
+
+ ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets,
+ pcide_bases[i]+0x206,
+ 0, NULL, q40ide_default_irq(pcide_bases[i]));
+ ide_register_hw(&hw, NULL);
}
- return 0;
}
+
return -EINVAL;
}
- if (check_region(io, 2))
+ if (request_region(io, 2, "rtrack"))
{
printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
return -EBUSY;
rtrack_radio.priv=&rtrack_unit;
if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO)==-1)
+ {
+ release_region(io, 2);
return -EINVAL;
-
- request_region(io, 2, "rtrack");
+ }
printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n");
/* Set up the I/O locking */
return -EINVAL;
}
- if (check_region(io, 2))
+ if (request_region(io, 2, "aztech"))
{
printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
return -EBUSY;
aztech_radio.priv=&aztech_unit;
if(video_register_device(&aztech_radio, VFL_TYPE_RADIO)==-1)
+ {
+ release_region(io,2);
return -EINVAL;
+ }
- request_region(io, 2, "aztech");
printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
/* mute card - prevents noisy bootups */
outb (0, io);
#include <linux/videodev.h> /* kernel radio structs */
#include <linux/config.h> /* CONFIG_RADIO_CADET_PORT */
#include <linux/param.h>
+#include <linux/isapnp.h>
#ifndef CONFIG_RADIO_CADET_PORT
#define CONFIG_RADIO_CADET_PORT 0x330
static unsigned char rdsbuf[RDS_BUFFER];
static int cadet_lock=0;
-#ifndef MODULE
static int cadet_probe(void);
-#endif
-
-#ifdef CONFIG_ISAPNP
-#include <linux/isapnp.h>
-
-struct pci_dev *dev;
+static struct pci_dev *dev;
static int isapnp_cadet_probe(void);
-#endif
/*
* Signal Strength Threshold Values
ioctl: cadet_ioctl,
};
-#ifdef CONFIG_ISAPNP
static int isapnp_cadet_probe(void)
{
dev = isapnp_find_dev (NULL, ISAPNP_VENDOR('M','S','M'),
return io;
}
-#endif /* CONFIG_ISAPNP */
-#ifdef MODULE
static int cadet_probe(void)
{
static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
for(i=0;i<8;i++) {
io=iovals[i];
- if(check_region(io,2)>=0) {
+ if(request_region(io,2, "cadet-probe")>=0) {
cadet_setfreq(1410);
if(cadet_getfreq()==1410) {
+ release_region(io, 2);
return io;
}
+ release_region(io, 2);
}
}
return -1;
}
-#endif /* MODULE */
static int __init cadet_init(void)
{
-#ifdef CONFIG_ISAPNP
- io = isapnp_cadet_probe();
-
+ /*
+ * If a probe was requested then probe ISAPnP first (safest)
+ */
if (io < 0)
- return (io);
-#else
-#ifndef MODULE /* only probe on non-ISAPnP monolithic compiles */
- io = cadet_probe ();
-#endif /* MODULE */
-#endif /* CONFIG_ISAPNP */
+ io = isapnp_cadet_probe();
+ /*
+ * If that fails then probe unsafely if probe is requested
+ */
+ if(io < 0)
+ io = cadet_probe ();
+ /*
+ * Else we bail out
+ */
+
if(io < 0) {
#ifdef MODULE
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
video_unregister_device(&cadet_radio);
release_region(io,2);
-#ifdef CONFIG_ISAPNP
if (dev)
dev->deactivate(dev);
-#endif
}
module_init(cadet_init);
return -EINVAL;
}
- if (check_region(io, 4))
+ if (request_region(io, 4, "gemtek"))
{
printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
return -EBUSY;
gemtek_radio.priv=&gemtek_unit;
if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO)==-1)
+ {
+ release_region(io, 4);
return -EINVAL;
-
- request_region(io, 4, "gemtek");
+ }
printk(KERN_INFO "GemTek Radio Card driver.\n");
spin_lock_init(&lock);
printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
return -EINVAL;
}
- if (check_region(io, 4))
+ if (request_region(io, 4, "rtrack2"))
{
printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
return -EBUSY;
spin_lock_init(&lock);
if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO)==-1)
+ {
+ release_region(io, 4);
return -EINVAL;
+ }
- request_region(io, 4, "rtrack2");
printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n");
/* mute card - prevents noisy bootups */
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
return -EINVAL;
}
- if (check_region(io, 2))
+ if (request_region(io, 2, "fmi"))
{
printk(KERN_ERR "fmi: port 0x%x already in use\n", io);
return -EBUSY;
init_MUTEX(&lock);
if(video_register_device(&fmi_radio, VFL_TYPE_RADIO)==-1)
+ {
+ release_region(io, 2);
return -EINVAL;
+ }
- request_region(io, 2, "fmi");
printk(KERN_INFO "SF16FMx radio card driver at 0x%x.\n", io);
printk(KERN_INFO "(c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz.\n");
/* mute card - prevents noisy bootups */
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
return -EINVAL;
}
- if (check_region(io, 2))
+ if (request_region(io, 2, "terratec"))
{
printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
return -EBUSY;
spin_lock_init(&lock);
if(video_register_device(&terratec_radio, VFL_TYPE_RADIO)==-1)
+ {
+ release_region(io,2);
return -EINVAL;
+ }
- request_region(io, 2, "terratec");
printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
/* mute card - prevents noisy bootups */
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
return -EINVAL;
}
- if(check_region(io, 2)) {
+ if(request_region(io, 2, "Trust FM Radio")) {
printk(KERN_ERR "trust: port 0x%x already in use\n", io);
return -EBUSY;
}
if(video_register_device(&trust_radio, VFL_TYPE_RADIO)==-1)
+ {
+ release_region(io, 2);
return -EINVAL;
-
- request_region(io, 2, "Trust FM Radio");
+ }
printk(KERN_INFO "Trust FM Radio card driver v1.0.\n");
printk(KERN_INFO BANNER);
io = typhoon_unit.iobase;
- if (check_region(io, 8)) {
+ if (request_region(io, 8, "typhoon")) {
printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n",
typhoon_unit.iobase);
return -EBUSY;
typhoon_radio.priv = &typhoon_unit;
if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1)
+ {
+ release_region(io, 8);
return -EINVAL;
-
- request_region(typhoon_unit.iobase, 8, "typhoon");
+ }
printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase);
printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n",
typhoon_unit.mutefreq);
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
return -EINVAL;
}
- if (check_region(io, 2)) {
- printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
- return -EBUSY;
- }
if ((io != 0x20c) && (io != 0x30c)) {
printk(KERN_ERR "zoltrix: invalid port, try 0x20c or 0x30c\n");
return -ENXIO;
}
+
zoltrix_radio.priv = &zoltrix_unit;
+ if (request_region(io, 2, "zoltrix")) {
+ printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
+ return -EBUSY;
+ }
if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO) == -1)
+ {
+ release_region(io, 2);
return -EINVAL;
-
- request_region(io, 2, "zoltrix");
+ }
printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
init_MUTEX(&zoltrix_unit.lock);
case VIDIOCGWIN:
{
struct video_window vw;
- vw.x=0;
- vw.y=0;
+ memset(&vw, 0, sizeof(vw));
vw.width=qcam->width/qcam->transfer_scale;
vw.height=qcam->height/qcam->transfer_scale;
- vw.chromakey=0;
- vw.flags=0;
if(copy_to_user(arg, &vw, sizeof(vw)))
return -EFAULT;
return 0;
case VIDIOCGWIN:
{
struct video_window vw;
- vw.x=0;
- vw.y=0;
+ memset(&vw, 0, sizeof(vw));
vw.width=qcam->width;
vw.height=qcam->height;
- vw.chromakey=0;
- vw.flags=0;
if(copy_to_user(arg, &vw, sizeof(vw)))
return -EFAULT;
return 0;
static const char *version =
"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"
-"eepro100.c: $Revision: 1.33 $ 2000/05/24 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
+"eepro100.c: $Revision: 1.35 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
/* A few user-configurable values that apply to all boards.
First set is undocumented and spelled per Intel recommendations. */
-static int congenb; /* Enable congestion control in the DP83840. */
+static int congenb /* = 0 */; /* Enable congestion control in the DP83840. */
static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */
static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */
/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
static int txdmacount = 128;
-static int rxdmacount;
+static int rxdmacount /* = 0 */;
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
Lower values use more memory, but are faster. */
+#if defined(__alpha__) || defined(__sparc__)
+static int rx_copybreak = 1518;
+#else
static int rx_copybreak = 200;
+#endif
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;
}
#endif /* CONFIG_EEPRO100_PM */
-#ifndef pci_resource_start
-#define pci_resource_start(p, n) (p)->resource[n].start
-#define pci_resource_len(p, n) ((p)->resource[n].end - (p)->resource[n].start)
-#endif
-
-/* Because of changes in this area the driver may not compile for kernels
- 2.3.43 - 2.3.47. --SAW */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
-#define netif_wake_queue(dev) do { \
- clear_bit(0, (void*)&dev->tbusy); \
- mark_bh(NET_BH); \
- } while(0)
-#define netif_start_queue(dev) clear_bit(0, (void*)&dev->tbusy)
-#define netif_stop_queue(dev) set_bit(0, (void*)&dev->tbusy)
-#define netif_running(dev) dev->start
-#define netdevice_start(dev) dev->start = 1
-#define netdevice_stop(dev) dev->start = 0
-#define netif_set_tx_timeout(dev, tf, tm)
-#define dev_kfree_skb_irq(x) dev_kfree_skb(x)
-#else
#define netdevice_start(dev)
#define netdevice_stop(dev)
#define netif_set_tx_timeout(dev, tf, tm) \
(dev)->tx_timeout = (tf); \
(dev)->watchdog_timeo = (tm); \
} while(0)
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,47)
#define netif_device_attach(dev) netif_start_queue(dev)
#define netif_device_detach(dev) netif_stop_queue(dev)
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
-typedef u32 dma_addr_t;
-static void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
- dma_addr_t *dma_handle)
-{
- void *ret;
- ret = kmalloc(size, GFP_ATOMIC);
- if (ret != NULL) {
- *dma_handle = virt_to_bus(ret);
- }
- return ret;
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- kfree(vaddr);
-}
-
-#define PCI_DMA_FROMDEVICE 0
-#define PCI_DMA_TODEVICE 0
-
-extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
- size_t size, int direction)
-{
- return virt_to_bus(ptr);
-}
-
-extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
- size_t size, int direction)
-{
-}
-
-extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
- dma_addr_t dma_handle,
- size_t size, int direction)
-{
-}
-#endif
#ifndef PCI_DEVICE_ID_INTEL_ID1029
#define PCI_DEVICE_ID_INTEL_ID1029 0x1029
TxUnderrun=0x1000, StatusComplete=0x8000,
};
+#define CONFIG_DATA_SIZE 22
struct TxFD { /* Transmit frame descriptor set. */
s32 status;
u32 link; /* void * */
s32 tx_buf_size0; /* Length of Tx frame. */
u32 tx_buf_addr1; /* void *, frame to be transmitted. */
s32 tx_buf_size1; /* Length of Tx frame. */
+ /* the structure must have space for at least CONFIG_DATA_SIZE starting
+ * from tx_desc_addr field */
};
/* Multicast filter setting block. --SAW */
/* The parameters for a CmdConfigure operation.
There are so many options that it would be difficult to document each bit.
We mostly use the default or recommended settings. */
-const char i82557_config_cmd[22] = {
+const char i82557_config_cmd[CONFIG_DATA_SIZE] = {
22, 0x08, 0, 0, 0, 0, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */
0, 0x2E, 0, 0x60, 0,
0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */
0x3f, 0x05, };
-const char i82558_config_cmd[22] = {
+const char i82558_config_cmd[CONFIG_DATA_SIZE] = {
22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */
0, 0x2E, 0, 0x60, 0x08, 0x88,
0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */
static int eepro100_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent);
static void eepro100_remove_one (struct pci_dev *pdev);
-
#ifdef CONFIG_EEPRO100_PM
static void eepro100_suspend (struct pci_dev *pdev);
static void eepro100_resume (struct pci_dev *pdev);
-#endif /* CONFIG_EEPRO100_PM */
+#endif
static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
static int mdio_read(long ioaddr, int phy_id, int location);
unsigned long ioaddr;
int irq;
int acpi_idle_state = 0, pm;
- static int cards_found;
+ static int cards_found /* = 0 */;
- static int did_version; /* Already printed version info. */
+ static int did_version /* = 0 */; /* Already printed version info. */
if (speedo_debug > 0 && did_version++ == 0)
printk(version);
This takes less than 10usec and will easily finish before the next
action. */
outl(PortReset, ioaddr + SCBPort);
+ udelay(10);
if (eeprom[3] & 0x0100)
product = "OEM i82557/i82558 10/100 Ethernet";
#endif /* kernel_bloat */
outl(PortReset, ioaddr + SCBPort);
+ udelay(10);
/* Return the chip to its original power state. */
pci_set_power_state(pdev, acpi_idle_state);
sp->tx_ring = tx_ring_space;
sp->tx_ring_dma = tx_ring_dma;
sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE);
- sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE);
+ sp->lstats_dma = cpu_to_le32(TX_RING_ELEM_DMA(sp, TX_RING_SIZE));
+ init_timer(&sp->timer); /* used in ioctl() */
sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
if (card_idx >= 0) {
io_outw(EE_ENB, ee_addr); udelay(2);
/* Terminate the EEPROM access. */
- io_outw(EE_ENB & ~EE_CS, ee_addr); udelay(4);
+ io_outw(EE_ENB & ~EE_CS, ee_addr);
return retval;
}
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
long ioaddr = dev->base_addr;
+ int retval;
if (speedo_debug > 1)
printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
sp->in_interrupt = 0;
/* .. we can safely take handler calls during init. */
- if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
+ retval = request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev);
+ if (retval) {
MOD_DEC_USE_COUNT;
- return -EBUSY;
+ return retval;
}
dev->if_port = sp->default_port;
to an alternate media type
2) to monitor Rx activity, and restart the Rx process if the receiver
hangs. */
- init_timer(&sp->timer);
sp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
sp->timer.data = (unsigned long)dev;
sp->timer.function = &speedo_timer; /* timer handler */
/* Set the segment registers to '0'. */
wait_for_cmd_done(ioaddr + SCBCmd);
outl(0, ioaddr + SCBPointer);
+ inl(ioaddr + SCBPointer); /* XXX */
outb(RxAddrLoad, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr + SCBCmd);
outb(CUCmdBase, ioaddr + SCBCmd);
- wait_for_cmd_done(ioaddr + SCBCmd);
/* Load the statistics block and rx ring addresses. */
+ wait_for_cmd_done(ioaddr + SCBCmd);
outl(sp->lstats_dma, ioaddr + SCBPointer);
+ inl(ioaddr + SCBPointer); /* XXX */
outb(CUStatsAddr, ioaddr + SCBCmd);
sp->lstats->done_marker = 0;
- wait_for_cmd_done(ioaddr + SCBCmd);
if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
if (speedo_debug > 2)
printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
dev->name);
} else {
+ wait_for_cmd_done(ioaddr + SCBCmd);
outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
ioaddr + SCBPointer);
outb(RxStart, ioaddr + SCBCmd);
- wait_for_cmd_done(ioaddr + SCBCmd);
}
+ wait_for_cmd_done(ioaddr + SCBCmd);
outb(CUDumpStats, ioaddr + SCBCmd);
+ udelay(30);
/* Fill the first command with our physical address. */
{
/* We haven't received a packet in a Long Time. We might have been
bitten by the receiver hang bug. This can be cleared by sending
a set multicast list command. */
- if (speedo_debug > 2)
+ if (speedo_debug > 3)
printk(KERN_DEBUG "%s: Sending a multicast list set command"
- " from a timer routine.\n", dev->name);
+ " from a timer routine,"
+ " m=%d, j=%ld, l=%ld.\n",
+ dev->name, sp->rx_mode, jiffies, sp->last_rx_time);
set_rx_mode(dev);
}
/* We must continue to monitor the media. */
sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */
add_timer(&sp->timer);
+#if defined(timer_exit)
+ timer_exit(&sp->timer);
+#endif
}
static void speedo_show_state(struct net_device *dev)
(unsigned)sp->rx_ringp[i]->status : 0);
#if 0
- long ioaddr = dev->base_addr;
- int phy_num = sp->phy[0] & 0x1f;
- for (i = 0; i < 16; i++) {
- /* FIXME: what does it mean? --SAW */
- if (i == 6) i = 21;
- printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n",
- dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i));
+ {
+ long ioaddr = dev->base_addr;
+ int phy_num = sp->phy[0] & 0x1f;
+ for (i = 0; i < 16; i++) {
+ /* FIXME: what does it mean? --SAW */
+ if (i == 6) i = 21;
+ printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n",
+ dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i));
+ }
}
#endif
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
struct RxFD *rxf, *last_rxf = NULL;
+ dma_addr_t last_rxf_dma = 0 /* to shut up the compiler */;
int i;
sp->cur_rx = 0;
rxf = (struct RxFD *)skb->tail;
sp->rx_ringp[i] = rxf;
sp->rx_ring_dma[i] =
- pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+ pci_map_single(sp->pdev, rxf,
+ PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_BIDIRECTIONAL);
skb_reserve(skb, sizeof(struct RxFD));
if (last_rxf) {
last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]);
- pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i-1], sizeof(struct RxFD), PCI_DMA_TODEVICE);
+ pci_dma_sync_single(sp->pdev, last_rxf_dma,
+ sizeof(struct RxFD), PCI_DMA_TODEVICE);
}
last_rxf = rxf;
+ last_rxf_dma = sp->rx_ring_dma[i];
rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */
rxf->link = 0; /* None yet. */
/* This field unused by i82557. */
rxf->rx_buf_addr = 0xffffffff;
rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
- pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i], sizeof(struct RxFD), PCI_DMA_TODEVICE);
+ pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i],
+ sizeof(struct RxFD), PCI_DMA_TODEVICE);
}
sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
/* Mark the last entry as end-of-list. */
last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */
- pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], sizeof(struct RxFD), PCI_DMA_TODEVICE);
+ pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1],
+ sizeof(struct RxFD), PCI_DMA_TODEVICE);
sp->last_rxf = last_rxf;
- sp->last_rxf_dma = sp->rx_ring_dma[RX_RING_SIZE-1];
+ sp->last_rxf_dma = last_rxf_dma;
}
static void speedo_purge_tx(struct net_device *dev)
sp->dirty_tx, sp->cur_tx,
sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
- /* Trigger a stats dump to give time before the reset. */
- speedo_get_stats(dev);
-
speedo_show_state(dev);
#if 0
if ((status & 0x00C0) != 0x0080
#else
{
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
- start_bh_atomic();
- /* Ensure that timer routine doesn't run! */
- del_timer(&sp->timer);
- end_bh_atomic();
-#else /* LINUX_VERSION_CODE */
del_timer_sync(&sp->timer);
-#endif /* LINUX_VERSION_CODE */
/* Reset the Tx and Rx units. */
outl(PortReset, ioaddr + SCBPort);
/* We may get spurious interrupts here. But I don't think that they
long ioaddr = dev->base_addr;
int entry;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
- if (test_bit(0, (void*)&dev->tbusy) != 0) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < TX_TIMEOUT - 2)
- return 1;
- if (tickssofar < TX_TIMEOUT) {
- /* Reap sent packets from the full Tx queue. */
- unsigned long flags;
- spin_lock_irqsave(&sp->lock, flags);
- wait_for_cmd_done(ioaddr + SCBCmd);
- outw(SCBTriggerIntr, ioaddr + SCBCmd);
- spin_unlock_irqrestore(&sp->lock, flags);
- return 1;
- }
- speedo_tx_timeout(dev);
- return 1;
- }
-#endif
-
{ /* Prevent interrupts from changing the Tx ring from underneath us. */
unsigned long flags;
/* Clear all interrupt sources. */
/* Will change from 0xfc00 to 0xff00 when we start handling
FCP and ER interrupts --Dragan */
- outl(0xfc00, ioaddr + SCBStatus);
+ outw(0xfc00, ioaddr + SCBStatus);
break;
}
} while (1);
skb->dev = dev;
skb_reserve(skb, sizeof(struct RxFD));
rxf->rx_buf_addr = 0xffffffff;
- pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], sizeof(struct RxFD), PCI_DMA_TODEVICE);
+ pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
+ sizeof(struct RxFD), PCI_DMA_TODEVICE);
return rxf;
}
rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
sp->last_rxf->link = cpu_to_le32(rxf_dma);
sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
- pci_dma_sync_single(sp->pdev, sp->last_rxf_dma, sizeof(struct RxFD), PCI_DMA_TODEVICE);
+ pci_dma_sync_single(sp->pdev, sp->last_rxf_dma,
+ sizeof(struct RxFD), PCI_DMA_TODEVICE);
sp->last_rxf = rxf;
sp->last_rxf_dma = rxf_dma;
}
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
int entry = sp->cur_rx % RX_RING_SIZE;
- int status;
int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
int alloc_ok = 1;
printk(KERN_DEBUG " In speedo_rx().\n");
/* If we own the next entry, it's a new packet. Send it up. */
while (sp->rx_ringp[entry] != NULL) {
+ int status;
int pkt_len;
pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+ status = le32_to_cpu(sp->rx_ringp[entry]->status);
+ pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
- if(!((status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete)) {
+ if (!(status & RxComplete))
break;
- }
-
- pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
if (--rx_work_limit < 0)
break;
pkt_len);
#endif
} else {
- void *temp;
/* Pass up the already-filled skbuff. */
skb = sp->rx_skbuff[entry];
if (skb == NULL) {
break;
}
sp->rx_skbuff[entry] = NULL;
- temp = skb_put(skb, pkt_len);
+ skb_put(skb, pkt_len);
sp->rx_ringp[entry] = NULL;
pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry],
PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
dev->name, inw(ioaddr + SCBStatus));
/* Shut off the media monitoring timer. */
- del_timer(&sp->timer);
+ del_timer_sync(&sp->timer);
/* Shutting down the chip nicely fails to disable flow control. So.. */
outl(PortPartialReset, ioaddr + SCBPort);
update the stats with the previous dump results, and then trigger a
new dump.
- These problems are mitigated by the current /proc implementation, which
- calls this routine first to judge the output length, and then to emit the
- output.
-
Oh, and incoming frames are dropped while executing dump-stats!
*/
static struct net_device_stats *
u16 *data = (u16 *)&rq->ifr_data;
int phy = sp->phy[0] & 0x1f;
int saved_acpi;
+ int t;
switch(cmd) {
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
They are currently serialized only with MDIO access from the
timer routine. 2000/05/09 SAW */
saved_acpi = pci_set_power_state(sp->pdev, 0);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
- start_bh_atomic();
+ t = del_timer_sync(&sp->timer);
data[3] = mdio_read(ioaddr, data[0], data[1]);
- end_bh_atomic();
-#else /* LINUX_VERSION_CODE */
- del_timer_sync(&sp->timer);
- data[3] = mdio_read(ioaddr, data[0], data[1]);
- add_timer(&sp->timer); /* may be set to the past --SAW */
-#endif /* LINUX_VERSION_CODE */
+ if (t)
+ add_timer(&sp->timer); /* may be set to the past --SAW */
pci_set_power_state(sp->pdev, saved_acpi);
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
saved_acpi = pci_set_power_state(sp->pdev, 0);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
- start_bh_atomic();
- mdio_write(ioaddr, data[0], data[1], data[2]);
- end_bh_atomic();
-#else /* LINUX_VERSION_CODE */
- del_timer_sync(&sp->timer);
+ t = del_timer_sync(&sp->timer);
mdio_write(ioaddr, data[0], data[1], data[2]);
- add_timer(&sp->timer); /* may be set to the past --SAW */
-#endif /* LINUX_VERSION_CODE */
+ if (t)
+ add_timer(&sp->timer); /* may be set to the past --SAW */
pci_set_power_state(sp->pdev, saved_acpi);
return 0;
default:
cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
/* Construct a full CmdConfig frame. */
- memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd));
+ memcpy(config_cmd_data, i82558_config_cmd, CONFIG_DATA_SIZE);
config_cmd_data[1] = (txfifo << 4) | rxfifo;
config_cmd_data[4] = rxdmacount;
config_cmd_data[5] = txdmacount + 0x80;
mc_setup_frm->link =
cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
- pci_dma_sync_single(sp->pdev, mc_blk->frame_dma, mc_blk->len, PCI_DMA_TODEVICE);
+ pci_dma_sync_single(sp->pdev, mc_blk->frame_dma,
+ mc_blk->len, PCI_DMA_TODEVICE);
wait_for_cmd_done(ioaddr + SCBCmd);
clear_suspend(last_cmd);
sp->rx_mode = new_rx_mode;
}
\f
-
#ifdef CONFIG_EEPRO100_PM
-
static void eepro100_suspend(struct pci_dev *pdev)
{
struct net_device *dev = pdev->driver_data;
sp->flow_ctrl = sp->partner = 0;
set_rx_mode(dev);
}
-
#endif /* CONFIG_EEPRO100_PM */
static void __devexit eepro100_remove_one (struct pci_dev *pdev)
id_table: eepro100_pci_tbl,
probe: eepro100_init_one,
remove: eepro100_remove_one,
-
#ifdef CONFIG_EEPRO100_PM
suspend: eepro100_suspend,
resume: eepro100_resume,
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == IRTTY_MAGIC, return -1;);
- IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+ IRDA_DEBUG(3, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
/* Disable interrupts & save flags */
save_flags(flags);
switch_bank(iobase, BANK0);
/* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */
- switch_bank(iobase, BANK0);
+ switch_bank(iobase, BANK0);
outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
-
+
+ outb(0x03, iobase+LCR); /* 8 bit word length */
+ outb(MCR_SIR, iobase+MCR); /* Start at SIR-mode, also clears LSR*/
+
/* Set FIFO size to 32 */
switch_bank(iobase, BANK2);
outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
switch_bank(iobase, BANK6);
outb(0x20, iobase+0); /* Set 32 bits FIR CRC */
outb(0x0a, iobase+1); /* Set MIR pulse width */
- outb(0x0d, iobase+2); /* Set SIR pulse width */
+ outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */
outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */
MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
dongle_types[dongle_id]);
break;
case 0x04: /* Sharp RY5HD01 */
- IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
- dongle_types[dongle_id]);
break;
case 0x05: /* Reserved, but this is what the Thinkpad reports */
IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
dongle_types[dongle_id]);
break;
case 0x04: /* Sharp RY5HD01 */
- IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
- dongle_types[dongle_id]);
+ break;
case 0x05: /* Reserved */
IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
dongle_types[dongle_id]);
#if defined(CONFIG_TMS380TR) || defined(CONFIG_TMS380TR_MODULE)
-unsigned char tms380tr_code[] = {
+static unsigned char tms380tr_code[] = {
0x00, 0x00, 0x00, 0xA0, 0x00, 0x20, 0x68, 0x54,
0x73, 0x69, 0x63, 0x20, 0x64, 0x6F, 0x20, 0x65,
0x73, 0x69, 0x72, 0x20, 0x6C, 0x65, 0x61, 0x65,
* Support routines for initializing a PCI subsystem.
*/
+/*
+ * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+ * PCI-PCI bridges cleanup, sorted resource allocation
+ */
+
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
+#include <linux/slab.h>
-#define DEBUG_CONFIG 0
+#define DEBUG_CONFIG 1
#if DEBUG_CONFIG
# define DBGC(args) printk args
#else
# define DBGC(args)
#endif
-
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
-#define ROUND_DOWN(x, a) ((x) & ~((a) - 1))
-static void __init
-pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
+static int __init
+pbus_assign_resources_sorted(struct pci_bus *bus,
+ struct pbus_set_ranges_data *ranges)
{
- struct pbus_set_ranges_data inner;
- struct pci_dev *dev;
struct list_head *ln;
+ struct resource *res;
+ struct resource_list head_io, head_mem, *list, *tmp;
+ unsigned long io_reserved = 0, mem_reserved = 0;
+ int idx, found_vga = 0;
- inner.found_vga = 0;
- inner.mem_start = inner.io_start = ~0UL;
- inner.mem_end = inner.io_end = 0;
-
- /* Collect information about how our direct children are layed out. */
+ head_io.next = head_mem.next = NULL;
for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
- int i;
- dev = pci_dev_b(ln);
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *res = &dev->resource[i];
- if (res->flags & IORESOURCE_IO) {
- if (res->start < inner.io_start)
- inner.io_start = res->start;
- if (res->end > inner.io_end)
- inner.io_end = res->end;
- } else if (res->flags & IORESOURCE_MEM) {
- if (res->start < inner.mem_start)
- inner.mem_start = res->start;
- if (res->end > inner.mem_end)
- inner.mem_end = res->end;
- }
+ struct pci_dev *dev = pci_dev_b(ln);
+ u16 cmd;
+
+ /* First, disable the device to avoid side
+ effects of possibly overlapping I/O and
+ memory ranges.
+ Except the VGA - for obvious reason. :-) */
+ if (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA)
+ found_vga = 1;
+ else {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY
+ | PCI_COMMAND_MASTER);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+
+ /* Reserve some resources for CardBus.
+ Are these values reasonable? */
+ if (dev->class >> 8 == PCI_CLASS_BRIDGE_CARDBUS) {
+ io_reserved += 8*1024;
+ mem_reserved += 32*1024*1024;
+ continue;
}
- if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
- inner.found_vga = 1;
+
+ pdev_sort_resources(dev, &head_io, IORESOURCE_IO);
+ pdev_sort_resources(dev, &head_mem, IORESOURCE_MEM);
}
- /* And for all of the sub-busses. */
- for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
- pbus_set_ranges(pci_bus_b(ln), &inner);
-
- /* Align the values. */
- inner.io_start = ROUND_DOWN(inner.io_start, 4*1024);
- inner.io_end = ROUND_UP(inner.io_end, 4*1024);
-
- inner.mem_start = ROUND_DOWN(inner.mem_start, 1*1024*1024);
- inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024);
-
- pcibios_fixup_pbus_ranges(bus, &inner);
-
- /* Configure the bridge, if possible. */
- if (bus->self) {
- struct pci_dev *bridge = bus->self;
- u32 l;
-
- /* Set up the top and bottom of the PCI I/O segment
- for this bus. */
- pci_read_config_dword(bridge, PCI_IO_BASE, &l);
- l &= 0xffff0000;
- l |= (inner.io_start >> 8) & 0x00f0;
- l |= (inner.io_end - 1) & 0xf000;
- pci_write_config_dword(bridge, PCI_IO_BASE, l);
-
- /*
- * Clear out the upper 16 bits of IO base/limit.
- * Clear out the upper 32 bits of PREF base/limit.
- */
- pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
- pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
-
- /* Set up the top and bottom of the PCI Memory segment
- for this bus. */
- l = (inner.mem_start & 0xfff00000) >> 16;
- l |= (inner.mem_end - 1) & 0xfff00000;
- pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
-
- /*
- * Turn off downstream PF memory address range, unless
- * there is a VGA behind this bridge, in which case, we
- * enable the PREFETCH range to include BIOS ROM at C0000.
- *
- * NOTE: this is a bit of a hack, done with PREFETCH for
- * simplicity, rather than having to add it into the above
- * non-PREFETCH range, which could then be bigger than we want.
- * We might assume that we could relocate the BIOS ROM, but
- * that would depend on having it found by those who need it
- * (the DEC BIOS emulator would find it, but I do not know
- * about the Xservers). So, we do it this way for now... ;-)
- */
- l = (inner.found_vga) ? 0 : 0x0000ffff;
- pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
-
- /*
- * Tell bridge that there is an ISA bus in the system,
- * and (possibly) a VGA as well.
- */
- l = (inner.found_vga) ? 0x0c : 0x04;
- pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l);
-
- /*
- * Clear status bits,
- * turn on I/O enable (for downstream I/O),
- * turn on memory enable (for downstream memory),
- * turn on master enable (for upstream memory and I/O).
- */
- pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007);
+ for (list = head_io.next; list;) {
+ res = list->res;
+ idx = res - &list->dev->resource[0];
+ if (pci_assign_resource(list->dev, idx) == 0
+ && ranges->io_end < res->end)
+ ranges->io_end = res->end;
+ tmp = list;
+ list = list->next;
+ kfree(tmp);
+ }
+ for (list = head_mem.next; list;) {
+ res = list->res;
+ idx = res - &list->dev->resource[0];
+ if (pci_assign_resource(list->dev, idx) == 0
+ && ranges->mem_end < res->end)
+ ranges->mem_end = res->end;
+ tmp = list;
+ list = list->next;
+ kfree(tmp);
}
- if (outer) {
- outer->found_vga |= inner.found_vga;
- if (inner.io_start < outer->io_start)
- outer->io_start = inner.io_start;
- if (inner.io_end > outer->io_end)
- outer->io_end = inner.io_end;
- if (inner.mem_start < outer->mem_start)
- outer->mem_start = inner.mem_start;
- if (inner.mem_end > outer->mem_end)
- outer->mem_end = inner.mem_end;
+ ranges->io_end += io_reserved;
+ ranges->mem_end += mem_reserved;
+
+ /* PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
+ requires that if there is no I/O ports or memory behind the
+ bridge, corresponding range must be turned off by writing base
+ value greater than limit to the bridge's base/limit registers. */
+#if 1
+ /* But assuming that some hardware designed before 1998 might
+ not support this (very unlikely - at least all DEC bridges
+ are ok and I believe that was standard de-facto. -ink), we
+ must allow for at least one unit. */
+ if (ranges->io_end == ranges->io_start)
+ ranges->io_end += 1;
+ if (ranges->mem_end == ranges->mem_start)
+ ranges->mem_end += 1;
+#endif
+ ranges->io_end = ROUND_UP(ranges->io_end, 4*1024);
+ ranges->mem_end = ROUND_UP(ranges->mem_end, 1024*1024);
+
+ return found_vga;
+}
+
+/* Initialize bridges with base/limit values we have collected */
+static void __init
+pci_setup_bridge(struct pci_bus *bus)
+{
+ struct pbus_set_ranges_data ranges;
+ struct pci_dev *bridge = bus->self;
+ u32 l;
+
+ if (!bridge || (bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ return;
+ ranges.io_start = bus->resource[0]->start;
+ ranges.io_end = bus->resource[0]->end;
+ ranges.mem_start = bus->resource[1]->start;
+ ranges.mem_end = bus->resource[1]->end;
+ pcibios_fixup_pbus_ranges(bus, &ranges);
+
+ DBGC(("PCI: Bus %d, bridge: %s\n", bus->number, bridge->name));
+ DBGC((" IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end));
+ DBGC((" MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end));
+
+ /* Set up the top and bottom of the PCI I/O segment for this bus. */
+ pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+ l &= 0xffff0000;
+ l |= (ranges.io_start >> 8) & 0x00f0;
+ l |= ranges.io_end & 0xf000;
+ pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+ /* Clear upper 16 bits of I/O base/limit. */
+ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+
+ /* Clear out the upper 32 bits of PREF base/limit. */
+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+ pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
+
+ /* Set up the top and bottom of the PCI Memory segment
+ for this bus. */
+ l = (ranges.mem_start >> 16) & 0xfff0;
+ l |= ranges.mem_end & 0xfff00000;
+ pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+
+ /* Set up PREF base/limit. */
+ l = (bus->resource[2]->start >> 16) & 0xfff0;
+ l |= bus->resource[2]->end & 0xfff00000;
+ pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+ /* Check if we have VGA behind the bridge.
+ Enable ISA in either case. */
+ l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? 0x0c : 0x04;
+ pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l);
+}
+
+static void __init
+pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+{
+ struct list_head *ln;
+ int found_vga = pbus_assign_resources_sorted(bus, ranges);
+
+ if (!ranges->found_vga && found_vga) {
+ struct pci_bus *b;
+
+ ranges->found_vga = 1;
+ /* Propogate presence of the VGA to upstream bridges */
+ for (b = bus; b->parent; b = b->parent) {
+#if 0
+ /* ? Do we actually need to enable PF memory? */
+ b->resource[2]->start = 0;
+#endif
+ b->resource[0]->flags |= IORESOURCE_BUS_HAS_VGA;
+ }
+ }
+ for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
+ struct pci_bus *b = pci_bus_b(ln);
+
+ b->resource[0]->start = ranges->io_start = ranges->io_end;
+ b->resource[1]->start = ranges->mem_start = ranges->mem_end;
+
+ pbus_assign_resources(b, ranges);
+
+ b->resource[0]->end = ranges->io_end - 1;
+ b->resource[1]->end = ranges->mem_end - 1;
+
+ pci_setup_bridge(b);
}
}
-void __init
-pci_set_bus_ranges(void)
+void __init
+pci_assign_unassigned_resources(void)
{
+ struct pbus_set_ranges_data ranges;
struct list_head *ln;
+ struct pci_dev *dev;
+
+ for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) {
+ struct pci_bus *b = pci_bus_b(ln);
- for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
- pbus_set_ranges(pci_bus_b(ln), NULL);
+ ranges.io_start = b->resource[0]->start;
+ ranges.mem_start = b->resource[1]->start;
+ ranges.io_end = ranges.io_start;
+ ranges.mem_end = ranges.mem_start;
+ ranges.found_vga = 0;
+ pbus_assign_resources(b, &ranges);
+ }
+ pci_for_each_dev(dev) {
+ pdev_enable_device(dev);
+ }
+}
+
+/* Check whether the bridge supports I/O forwarding.
+ If not, its I/O base/limit register must be
+ read-only and read as 0. */
+unsigned long __init
+pci_bridge_check_io(struct pci_dev *bridge)
+{
+ u16 io;
+
+ pci_read_config_word(bridge, PCI_IO_BASE, &io);
+ if (!io) {
+ pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
+ pci_read_config_word(bridge, PCI_IO_BASE, &io);
+ pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
+ }
+ if (io)
+ return IORESOURCE_IO;
+ printk(KERN_WARNING "PCI: bridge %s does not support I/O forwarding!\n",
+ bridge->name);
+ return 0;
}
/* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
+/*
+ * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+ * Resource sorting
+ */
+
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
+#include <linux/slab.h>
-#define DEBUG_CONFIG 0
+#define DEBUG_CONFIG 1
#if DEBUG_CONFIG
# define DBGC(args) printk args
#else
}
}
- DBGC((" got res[%lx:%lx] for resource %d\n", res->start, res->end, i));
+ DBGC((" got res[%lx:%lx] for resource %d of %s\n", res->start,
+ res->end, i, dev->name));
return 0;
}
-void
-pdev_assign_unassigned_resources(struct pci_dev *dev)
+/* Sort resources of a given type by alignment */
+void __init
+pdev_sort_resources(struct pci_dev *dev,
+ struct resource_list *head, u32 type_mask)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *r;
+ struct resource_list *list, *tmp;
+
+ /* PCI-PCI bridges may have I/O ports or
+ memory on the primary bus */
+ if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI &&
+ i >= PCI_BRIDGE_RESOURCES)
+ continue;
+
+ r = &dev->resource[i];
+ if (!(r->flags & type_mask) || r->parent)
+ continue;
+ for (list = head; ; list = list->next) {
+ unsigned long size = 0;
+ struct resource_list *ln = list->next;
+
+ if (ln)
+ size = ln->res->end - ln->res->start;
+ if (r->end - r->start > size) {
+ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ tmp->next = ln;
+ tmp->res = r;
+ tmp->dev = dev;
+ list->next = tmp;
+ break;
+ }
+ }
+ }
+}
+
+void __init
+pdev_enable_device(struct pci_dev *dev)
{
u32 reg;
u16 cmd;
int i;
- DBGC(("PCI assign unassigned: (%s)\n", dev->name));
+ DBGC(("PCI enable device: (%s)\n", dev->name));
pci_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_IO;
else if (res->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
-
- /* If it is already assigned or the resource does
- not exist, there is nothing to do. */
- if (res->parent != NULL || res->flags == 0)
- continue;
-
- pci_assign_resource(dev, i);
}
/* Special case, disable the ROM. Several devices act funny
it, the bit will go into the bucket. */
cmd |= PCI_COMMAND_MASTER;
+ /* Set the cache line and default latency (32). */
+ pci_write_config_word(dev, PCI_CACHE_LINE_SIZE,
+ (32 << 8) | (L1_CACHE_BYTES / sizeof(u32)));
+
/* Enable the appropriate bits in the PCI command register. */
pci_write_config_word(dev, PCI_COMMAND, cmd);
DBGC((" cmd reg 0x%x\n", cmd));
-
- /* If this is a PCI bridge, set the cache line correctly. */
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
- (L1_CACHE_BYTES / sizeof(u32)));
- }
-}
-
-void __init
-pci_assign_unassigned_resources(void)
-{
- struct pci_dev *dev;
-
- pci_for_each_dev(dev) {
- pdev_assign_unassigned_resources(dev);
- }
}
{
int rdp = isapnp_rdp;
while (rdp <= 0x3ff) {
- if (!check_region(rdp, 1)) {
- isapnp_rdp = rdp;
- return 0;
- }
- rdp += RDP_STEP;
/*
* We cannot use NE2000 probe spaces for ISAPnP or we
* will lock up machines.
*/
- if(rdp >= 0x280 && rdp <= 0x380)
- continue;
+ if ((rdp < 0x280 || rdp > 0x380) && !check_region(rdp, 1))
+ {
+ isapnp_rdp = rdp;
+ return 0;
+ }
+ rdp += RDP_STEP;
}
return -1;
}
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o
+obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o
obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o
obj-$(CONFIG_CYBERSTORMII_SCSI) += NCR53C9x.o cyberstormII.o
obj-$(CONFIG_BLZ2060_SCSI) += NCR53C9x.o blz2060.o
#define HOSTS_C
-#include "a2091.h"
-
static Scsi_Host_Template driver_template = A2091_SCSI;
#include "scsi_module.c"
#ifndef A2091_H
+#define A2091_H
/* $Id: a2091.h,v 1.4 1997/01/19 23:07:09 davem Exp $
*
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
+#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/spinlock.h>
cache_push (addr, cmd->SCp.this_residual);
/* start DMA */
+ mb(); /* make sure setup is completed */
DMA(a3000_host)->ST_DMA = 1;
+ mb(); /* make sure DMA has started before next IO */
/* return success */
return 0;
cntr |= CNTR_DDIR;
DMA(instance)->CNTR = cntr;
+ mb(); /* make sure CNTR is updated before next IO */
/* flush if we were reading */
if (HDATA(instance)->dma_dir) {
DMA(instance)->FLUSH = 1;
+ mb(); /* don't allow prefetch */
while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
- ;
+ barrier();
+ mb(); /* no IO until FLUSH is done */
}
/* clear a possible interrupt */
/* stop DMA */
DMA(instance)->SP_DMA = 1;
+ mb(); /* make sure DMA is stopped before next IO */
/* restore the CONTROL bits (minus the direction flag) */
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+ mb(); /* make sure CNTR is updated before next IO */
/* copy from a bounce buffer, if necessary */
if (status && HDATA(instance)->dma_bounce_buffer) {
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
return 0;
+ if (!request_mem_region(0xDD0000, 256, "wd33c93"))
+ return -EBUSY;
tpnt->proc_name = "A3000";
tpnt->proc_info = &wd33c93_proc_info;
a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
- if(a3000_host == NULL)
+ if (a3000_host == NULL) {
+ release_mem_region(0xDD0000, 256);
return 0;
+ }
a3000_host->base = ZTWO_VADDR(0xDD0000);
a3000_host->irq = IRQ_AMIGA_PORTS;
DMA(a3000_host)->DAWR = DAWR_A3000;
#define HOSTS_C
-#include "a3000.h"
-
-static Scsi_Host_Template driver_template = A3000_SCSI;
+static Scsi_Host_Template driver_template = _A3000_SCSI;
#include "scsi_module.c"
#ifdef MODULE
wd33c93_release();
DMA(instance)->CNTR = 0;
+ release_mem_region(0xDD0000, 256);
free_irq(IRQ_AMIGA_PORTS, a3000_intr);
#endif
return 1;
#ifndef A3000_H
+#define A3000_H
/* $Id: a3000.h,v 1.4 1997/01/19 23:07:10 davem Exp $
*
#define CAN_QUEUE 16
#endif
-#define A3000_SCSI { proc_name: "A3000", \
+#define _A3000_SCSI { proc_name: "A3000", \
proc_info: NULL, \
name: "Amiga 3000 built-in SCSI", \
detect: a3000_detect, \
*/
if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) &&
!ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {
- atari_dma_buffer = atari_stram_alloc( STRAM_BUFFER_SIZE, NULL, "SCSI" );
+ atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
if (!atari_dma_buffer) {
printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
"double buffer\n" );
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
+ * 22 Nov 2000 Rev. 6.02 for linux 2.4.0-test11
+ * + Return code checked when calling pci_enable_device.
+ * + Removed old scsi error handling support.
+ * + The obsolete boot option flag eh:n is silently ignored.
+ * + Removed error messages while a disk drive is powered up at
+ * boot time.
+ * + Improved boot messages: all tagged capable device are
+ * indicated as "tagged" or "soft-tagged" :
+ * - "soft-tagged" means that the driver is trying to do its
+ * own tagging (i.e. the tc:y option is in effect);
+ * - "tagged" means that the device supports tagged commands,
+ * but the driver lets the HBA be responsible for tagging
+ * support.
+ *
* 16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18
* + Updated to the new __setup interface for boot command line options.
* + When loaded as a module, accepts the new parameter boot_options
* which value is a string with the same format of the kernel boot
* command line options. A valid example is:
- * modprobe eata 'boot_options=\"0x7410,0x230,lc:y,tc:n,mq:4\"'
+ * modprobe eata boot_options=\"0x7410,0x230,lc:y,tc:n,mq:4\"
*
* 9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17
* + 64bit cleanup for Linux/Alpha platform support
* This driver is based on the CAM (Common Access Method Committee)
* EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
*
- * Copyright (C) 1994-1999 Dario Ballabio (dario@milano.europe.dg.com)
+ * Copyright (C) 1994-2000 Dario Ballabio (ballabio_dario@emc.com)
+ *
+ * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that redistributions of source
* After the optional list of detection probes, other possible command line
* options are:
*
- * eh:y use new scsi code;
- * eh:n use old scsi code;
* et:y force use of extended translation (255 heads, 63 sectors);
* et:n use disk geometry detected by scsicam_bios_param;
* rs:y reverse scan order while detecting PCI boards;
*
* The default value is: "eata=lc:n,tc:n,mq:16,tm:0,et:n,rs:n".
* An example using the list of detection probes could be:
- * "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n,et:n".
+ * "eata=0x7410,0x230,lc:y,tc:n,mq:4,et:n".
*
* When loading as a module, parameters can be specified as well.
* The above example would be (use 1 in place of y and 0 in place of n):
*
* modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \
- * max_queue_depth=4 tag_mode=0 use_new_eh_code=0 \
+ * max_queue_depth=4 tag_mode=0 \
* ext_tran=0 rev_scan=1
*
* ----------------------------------------------------------------------------
#include <linux/version.h>
+#ifndef LinuxVersionCode
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
+
#define MAX_INT_PARAM 10
#if defined(MODULE)
MODULE_PARM(link_statistics, "i");
MODULE_PARM(max_queue_depth, "i");
MODULE_PARM(tag_mode, "i");
-MODULE_PARM(use_new_eh_code, "i");
MODULE_PARM(ext_tran, "i");
MODULE_PARM(rev_scan, "i");
MODULE_AUTHOR("Dario Ballabio");
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ctype.h>
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-#include <asm/spinlock.h>
-#else
#include <linux/spinlock.h>
-#endif
#define SPIN_FLAGS unsigned long spin_flags;
#define SPIN_LOCK spin_lock_irq(&io_request_lock);
#define ASOK 0x00
#define ASST 0x01
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-#define ARRAY_SIZE(x) (sizeof (x) / sizeof((x)[0]))
-#endif
-
#define YESNO(a) ((a) ? 'y' : 'n')
#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
static int tag_mode = TAG_MIXED;
static int ext_tran = FALSE;
static int rev_scan = TRUE;
-static int use_new_eh_code = TRUE;
static char *boot_options;
#if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
}
if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue)
- tag_suffix = ", tagged";
+ tag_suffix = ", soft-tagged";
else if (dev->tagged_supported && TLDEV(dev->type))
- tag_suffix = ", untagged";
+ tag_suffix = ", tagged";
printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n",
BN(j), host->host_no, dev->channel, dev->id, dev->lun,
addr = pci_resource_start (dev, 0);
- pci_enable_device (dev); /* XXX handle error */
+ if (pci_enable_device (dev)) continue;
#if defined(DEBUG_PCI_DETECT)
printk("%s: tune_pci_port, bus %d, devfn 0x%x, addr 0x%x.\n",
}
else tag_type = 'n';
- sh[j]->hostt->use_new_eh_code = use_new_eh_code;
-
if (j == 0) {
- printk("EATA/DMA 2.0x: Copyright (C) 1994-1999 Dario Ballabio.\n");
- printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c, rs:%c, et:%c.\n",
+ printk("EATA/DMA 2.0x: Copyright (C) 1994-2000 Dario Ballabio.\n");
+ printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c.\n",
driver_name, tag_type, YESNO(linked_comm), max_queue_depth,
- YESNO(use_new_eh_code), YESNO(rev_scan), YESNO(ext_tran));
+ YESNO(rev_scan), YESNO(ext_tran));
}
printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
else if (!strncmp(cur, "tm:", 3)) tag_mode = val;
else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val;
else if (!strncmp(cur, "ls:", 3)) link_statistics = val;
- else if (!strncmp(cur, "eh:", 3)) use_new_eh_code = val;
else if (!strncmp(cur, "et:", 3)) ext_tran = val;
else if (!strncmp(cur, "rs:", 3)) rev_scan = val;
return rtn;
}
-static inline int do_old_abort(Scsi_Cmnd *SCarg) {
- unsigned int i, j;
-
- j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
-
- if (SCarg->host_scribble == NULL ||
- (SCarg->serial_number_at_timeout &&
- (SCarg->serial_number != SCarg->serial_number_at_timeout))) {
- printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
- BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
- return SCSI_ABORT_NOT_RUNNING;
- }
-
- i = *(unsigned int *)SCarg->host_scribble;
- printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
- BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
-
- if (i >= sh[j]->can_queue)
- panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: abort, timeout error.\n", BN(j));
- return SCSI_ABORT_ERROR;
- }
-
- if (HD(j)->cp_stat[i] == FREE) {
- printk("%s: abort, mbox %d is free.\n", BN(j), i);
- return SCSI_ABORT_NOT_RUNNING;
- }
-
- if (HD(j)->cp_stat[i] == IN_USE) {
- printk("%s: abort, mbox %d is in use.\n", BN(j), i);
-
- if (SCarg != HD(j)->cp[i].SCpnt)
- panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
- BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
-
- if (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)
- printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
-
- return SCSI_ABORT_SNOOZE;
- }
-
- if (HD(j)->cp_stat[i] == IN_RESET) {
- printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
- return SCSI_ABORT_ERROR;
- }
-
- if (HD(j)->cp_stat[i] == LOCKED) {
- printk("%s: abort, mbox %d is locked.\n", BN(j), i);
- return SCSI_ABORT_NOT_RUNNING;
- }
-
- if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
- SCarg->result = DID_ABORT << 16;
- SCarg->host_scribble = NULL;
- HD(j)->cp_stat[i] = FREE;
- printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
- BN(j), i, SCarg->pid);
- SCarg->scsi_done(SCarg);
- return SCSI_ABORT_SUCCESS;
- }
-
- panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
-}
-
-int eata2x_old_abort(Scsi_Cmnd *SCarg) {
- int rtn;
-
- rtn = do_old_abort(SCarg);
- return rtn;
-}
-
static inline int do_abort(Scsi_Cmnd *SCarg) {
unsigned int i, j;
return do_abort(SCarg);
}
-static inline int do_old_reset(Scsi_Cmnd *SCarg) {
- unsigned int i, j, time, k, c, limit = 0;
- int arg_done = FALSE;
- Scsi_Cmnd *SCpnt;
-
- j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
- printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
- BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
-
- if (SCarg->host_scribble == NULL)
- printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
-
- if (SCarg->serial_number_at_timeout &&
- (SCarg->serial_number != SCarg->serial_number_at_timeout)) {
- printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
- return SCSI_RESET_NOT_RUNNING;
- }
-
- if (HD(j)->in_reset) {
- printk("%s: reset, exit, already in reset.\n", BN(j));
- return SCSI_RESET_ERROR;
- }
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: reset, exit, timeout error.\n", BN(j));
- return SCSI_RESET_ERROR;
- }
-
- HD(j)->retries = 0;
-
- for (c = 0; c <= sh[j]->max_channel; c++)
- for (k = 0; k < sh[j]->max_id; k++) {
- HD(j)->target_redo[k][c] = TRUE;
- HD(j)->target_to[k][c] = 0;
- }
-
- for (i = 0; i < sh[j]->can_queue; i++) {
-
- if (HD(j)->cp_stat[i] == FREE) continue;
-
- if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
- continue;
- }
-
- if (!(SCpnt = HD(j)->cp[i].SCpnt))
- panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
-
- if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
- HD(j)->cp_stat[i] = ABORTING;
- printk("%s: reset, mbox %d aborting, pid %ld.\n",
- BN(j), i, SCpnt->pid);
- }
-
- else {
- HD(j)->cp_stat[i] = IN_RESET;
- printk("%s: reset, mbox %d in reset, pid %ld.\n",
- BN(j), i, SCpnt->pid);
- }
-
- if (SCpnt->host_scribble == NULL)
- panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
-
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
-
- if (SCpnt->scsi_done == NULL)
- panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
-
- if (SCpnt == SCarg) arg_done = TRUE;
- }
-
- if (do_dma(sh[j]->io_port, 0, RESET_PIO)) {
- printk("%s: reset, cannot reset, timeout error.\n", BN(j));
- return SCSI_RESET_ERROR;
- }
-
- printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
-
-#if defined(DEBUG_RESET)
- do_trace = TRUE;
-#endif
-
- HD(j)->in_reset = TRUE;
- SPIN_UNLOCK
- time = jiffies;
- while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
- SPIN_LOCK
- printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
-
- for (i = 0; i < sh[j]->can_queue; i++) {
-
- if (HD(j)->cp_stat[i] == IN_RESET) {
- SCpnt = HD(j)->cp[i].SCpnt;
- SCpnt->result = DID_RESET << 16;
- SCpnt->host_scribble = NULL;
-
- /* This mailbox is still waiting for its interrupt */
- HD(j)->cp_stat[i] = LOCKED;
-
- printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
- }
-
- else if (HD(j)->cp_stat[i] == ABORTING) {
- SCpnt = HD(j)->cp[i].SCpnt;
- SCpnt->result = DID_RESET << 16;
- SCpnt->host_scribble = NULL;
-
- /* This mailbox was never queued to the adapter */
- HD(j)->cp_stat[i] = FREE;
-
- printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
- }
-
- else
-
- /* Any other mailbox has already been set free by interrupt */
- continue;
-
- SCpnt->scsi_done(SCpnt);
- }
-
- HD(j)->in_reset = FALSE;
- do_trace = FALSE;
-
- if (arg_done) {
- printk("%s: reset, exit, success.\n", BN(j));
- return SCSI_RESET_SUCCESS;
- }
- else {
- printk("%s: reset, exit, wakeup.\n", BN(j));
- return SCSI_RESET_PUNT;
- }
-}
-
-int eata2x_old_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
- int rtn;
-
- rtn = do_old_reset(SCarg);
- return rtn;
-}
-
static inline int do_reset(Scsi_Cmnd *SCarg) {
unsigned int i, j, time, k, c, limit = 0;
int arg_done = FALSE;
if (link_statistics) {
if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
- batchcount++; readycount += n_ready, seeknosort += seek / 1024;
+ batchcount++; readycount += n_ready; seeknosort += seek / 1024;
if (input_only) inputcount++;
if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
else seeksorted += (iseek + maxsec - minsec) / 1024;
if (tstatus == GOOD)
HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
- if (spp->target_status && SCpnt->device->type == TYPE_DISK)
+ if (spp->target_status && SCpnt->device->type == TYPE_DISK &&
+ (!(tstatus == CHECK_CONDITION && HD(j)->iocount <= 1000 &&
+ (SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
"target_status 0x%x, sense key 0x%x.\n", BN(j),
SCpnt->channel, SCpnt->target, SCpnt->lun,
#include "scsi_module.c"
#ifndef MODULE
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-void eata2x_setup(char *str, int *ints) {
- internal_setup(str, ints);
-}
-#else
__setup("eata=", option_setup);
-#endif
-
#endif /* end MODULE */
#define _EATA_H
#include <scsi/scsicam.h>
-#include <linux/version.h>
int eata2x_detect(Scsi_Host_Template *);
int eata2x_release(struct Scsi_Host *);
int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata2x_abort(Scsi_Cmnd *);
-int eata2x_old_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *);
-int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
int eata2x_biosparam(Disk *, kdev_t, int *);
-#define EATA_VERSION "5.11.00"
-
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#define EATA_VERSION "6.02.00"
#define EATA { \
name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
detect: eata2x_detect, \
release: eata2x_release, \
queuecommand: eata2x_queuecommand, \
- abort: eata2x_old_abort, \
- reset: eata2x_old_reset, \
+ abort: NULL, \
+ reset: NULL, \
eh_abort_handler: eata2x_abort, \
eh_device_reset_handler: NULL, \
eh_bus_reset_handler: NULL, \
continue;
release:
- release_mem_region(ZTWO_PADDR(instance->base), 256);
+ release_mem_region(address, 256);
}
return num_gvp11;
failed = 0;
while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
if (idescsi_cleanup (drive)) {
- printk ("%s: cleanup_module() called while still busy\n", drive->name);
+ printk ("%s: exit_idescsi_module() called while still busy\n", drive->name);
failed++;
}
}
--- /dev/null
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mvme147hw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "wd33c93.h"
+#include "mvme147.h"
+
+#include<linux/stat.h>
+
+#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+static struct Scsi_Host *mvme147_host = NULL;
+
+static void mvme147_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+ if (irq == MVME147_IRQ_SCSI_PORT)
+ wd33c93_intr (mvme147_host);
+ else
+ m147_pcc->dma_intr = 0x89; /* Ack and enable ints */
+}
+
+static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+{
+ unsigned char flags = 0x01;
+ unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+
+ /* setup dma direction */
+ if (!dir_in)
+ flags |= 0x04;
+
+ /* remember direction */
+ HDATA(mvme147_host)->dma_dir = dir_in;
+
+ if (dir_in)
+ /* invalidate any cache */
+ cache_clear (addr, cmd->SCp.this_residual);
+ else
+ /* push any dirty cache */
+ cache_push (addr, cmd->SCp.this_residual);
+
+ /* start DMA */
+ m147_pcc->dma_bcr = cmd->SCp.this_residual | (1<<24);
+ m147_pcc->dma_dadr = addr;
+ m147_pcc->dma_cntrl = flags;
+
+ /* return success */
+ return 0;
+}
+
+static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+ int status)
+{
+ m147_pcc->dma_cntrl = 0;
+}
+
+int mvme147_detect(Scsi_Host_Template *tpnt)
+{
+ static unsigned char called = 0;
+
+ if (!MACH_IS_MVME147 || called)
+ return 0;
+ called++;
+
+ tpnt->proc_name = "MVME147";
+ tpnt->proc_info = &wd33c93_proc_info;
+
+ mvme147_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
+ mvme147_host->base = 0xfffe4000;
+ mvme147_host->irq = MVME147_IRQ_SCSI_PORT;
+ wd33c93_init(mvme147_host, (wd33c93_regs *)0xfffe4000,
+ dma_setup, dma_stop, WD33C93_FS_8_10);
+
+ request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, "MVME147 SCSI PORT", mvme147_intr);
+ request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, "MVME147 SCSI DMA", mvme147_intr);
+#if 0 /* Disabled; causes problems booting */
+ m147_pcc->scsi_interrupt = 0x10; /* Assert SCSI bus reset */
+ udelay(100);
+ m147_pcc->scsi_interrupt = 0x00; /* Negate SCSI bus reset */
+ udelay(2000);
+ m147_pcc->scsi_interrupt = 0x40; /* Clear bus reset interrupt */
+#endif
+ m147_pcc->scsi_interrupt = 0x09; /* Enable interrupt */
+
+ m147_pcc->dma_cntrl = 0x00; /* ensure DMA is stopped */
+ m147_pcc->dma_intr = 0x89; /* Ack and enable ints */
+
+ return 1;
+}
+
+#define HOSTS_C
+
+#include "mvme147.h"
+
+static Scsi_Host_Template driver_template = MVME147_SCSI;
+
+#include "scsi_module.c"
+
+int mvme147_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+ /* XXX Make sure DMA is stopped! */
+ wd33c93_release();
+ free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
+ free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr);
+#endif
+ return 1;
+}
--- /dev/null
+#ifndef MVME147_H
+
+/* $Id: mvme147.h,v 1.4 1997/01/19 23:07:10 davem Exp $
+ *
+ * Header file for the MVME147 built-in SCSI controller for Linux
+ *
+ * Written and (C) 1993, Hamish Macdonald, see mvme147.c for more info
+ *
+ */
+
+#include <linux/types.h>
+
+int mvme147_detect(Scsi_Host_Template *);
+int mvme147_release(struct Scsi_Host *);
+const char *wd33c93_info(void);
+int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd33c93_abort(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#ifdef HOSTS_C
+
+#define MVME147_SCSI {proc_name: "MVME147", \
+ proc_info: NULL, \
+ name: "MVME147 built-in SCSI", \
+ detect: mvme147_detect, \
+ release: mvme147_release, \
+ queuecommand: wd33c93_queuecommand, \
+ abort: wd33c93_abort, \
+ reset: wd33c93_reset, \
+ can_queue: CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: CMD_PER_LUN, \
+ use_clustering: ENABLE_CLUSTERING }
+
+#endif /* else def HOSTS_C */
+
+#endif /* MVME147_H */
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
+ * 01 Nov 2000 Rev. 6.02 for linux 2.4.0-test11
+ * + Removed old scsi error handling support.
+ * + The obsolete boot option flag eh:n is silently ignored.
+ * + Removed error messages while a disk drive is powered up at
+ * boot time.
+ * + Improved boot messages: all tagged capable device are
+ * indicated as "tagged".
+ *
* 16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18
* + Updated to the new __setup interface for boot command line options.
* + When loaded as a module, accepts the new parameter boot_options
* which value is a string with the same format of the kernel boot
* command line options. A valid example is:
- * modprobe u14-34f 'boot_options=\"0x230,0x340,lc:y,mq:4\"'
+ * modprobe u14-34f boot_options=\"0x230,0x340,lc:y,mq:4\"
*
* 22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11
* + Removed pre-2.2 source code compatibility.
*
* Multiple U14F and/or U34F host adapters are supported.
*
- * Copyright (C) 1994-1999 Dario Ballabio (dario@milano.europe.dg.com)
+ * Copyright (C) 1994-2000 Dario Ballabio (ballabio_dario@emc.com)
+ *
+ * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that redistributions of source
* After the optional list of detection probes, other possible command line
* options are:
*
- * eh:y use new scsi code;
- * eh:n use old scsi code;
* et:y use disk geometry returned by scsicam_bios_param;
* et:n use disk geometry jumpered on the board;
* lc:y enables linked commands;
*
* The default value is: "u14-34f=lc:n,of:n,mq:8,et:n".
* An example using the list of detection probes could be:
- * "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n,et:n".
+ * "u14-34f=0x230,0x340,lc:y,of:n,mq:4,et:n".
*
* When loading as a module, parameters can be specified as well.
* The above example would be (use 1 in place of y and 0 in place of n):
*
* modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \
- * max_queue_depth=4 use_new_eh_code=0 ext_tran=0
+ * max_queue_depth=4 ext_tran=0
*
* ----------------------------------------------------------------------------
* In this implementation, linked commands are designed to work with any DISK
#include <linux/version.h>
+#ifndef LinuxVersionCode
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
+
#define MAX_INT_PARAM 10
#if defined(MODULE)
MODULE_PARM(have_old_firmware, "i");
MODULE_PARM(link_statistics, "i");
MODULE_PARM(max_queue_depth, "i");
-MODULE_PARM(use_new_eh_code, "i");
MODULE_PARM(ext_tran, "i");
MODULE_AUTHOR("Dario Ballabio");
#include <linux/config.h>
#include <linux/init.h>
#include <linux/ctype.h>
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-#include <asm/spinlock.h>
-#else
#include <linux/spinlock.h>
-#endif
#define SPIN_FLAGS unsigned long spin_flags;
#define SPIN_LOCK spin_lock_irq(&io_request_lock);
#define ASOK 0x00
#define ASST 0x91
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-#define ARRAY_SIZE(x) (sizeof (x) / sizeof((x)[0]))
-#endif
-
#define YESNO(a) ((a) ? 'y' : 'n')
#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
static int do_trace = FALSE;
static int setup_done = FALSE;
-static int link_statistics = 0;
+static int link_statistics;
static int ext_tran = FALSE;
-static int use_new_eh_code = TRUE;
-static char *boot_options = NULL;
+static char *boot_options;
#if defined(HAVE_OLD_UX4F_FIRMWARE)
static int have_old_firmware = TRUE;
}
if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue)
- tag_suffix = ", tagged";
+ tag_suffix = ", soft-tagged";
else if (dev->tagged_supported && TLDEV(dev->type))
- tag_suffix = ", untagged";
+ tag_suffix = ", tagged";
printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n",
BN(j), host->host_no, dev->channel, dev->id, dev->lun,
if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING;
- tpnt->use_new_eh_code = use_new_eh_code;
-
sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
if (sh[j] == NULL) {
if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
if (j == 0) {
- printk("UltraStor 14F/34F: Copyright (C) 1994-1999 Dario Ballabio.\n");
- printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c, et:%c.\n",
+ printk("UltraStor 14F/34F: Copyright (C) 1994-2000 Dario Ballabio.\n");
+ printk("%s config options -> of:%c, lc:%c, mq:%d, et:%c.\n",
driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
- max_queue_depth, YESNO(use_new_eh_code), YESNO(ext_tran));
+ max_queue_depth, YESNO(ext_tran));
}
printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n",
else if (!strncmp(cur, "of:", 3)) have_old_firmware = val;
else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val;
else if (!strncmp(cur, "ls:", 3)) link_statistics = val;
- else if (!strncmp(cur, "eh:", 3)) use_new_eh_code = val;
else if (!strncmp(cur, "et:", 3)) ext_tran = val;
if ((cur = strchr(cur, ','))) ++cur;
return rtn;
}
-static inline int do_old_abort(Scsi_Cmnd *SCarg) {
- unsigned int i, j;
-
- j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
-
- if (SCarg->host_scribble == NULL ||
- (SCarg->serial_number_at_timeout &&
- (SCarg->serial_number != SCarg->serial_number_at_timeout))) {
- printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
- BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
- return SCSI_ABORT_NOT_RUNNING;
- }
-
- i = *(unsigned int *)SCarg->host_scribble;
- printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
- BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
-
- if (i >= sh[j]->can_queue)
- panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: abort, timeout error.\n", BN(j));
- return SCSI_ABORT_ERROR;
- }
-
- if (HD(j)->cp_stat[i] == FREE) {
- printk("%s: abort, mbox %d is free.\n", BN(j), i);
- return SCSI_ABORT_NOT_RUNNING;
- }
-
- if (HD(j)->cp_stat[i] == IN_USE) {
- printk("%s: abort, mbox %d is in use.\n", BN(j), i);
-
- if (SCarg != HD(j)->cp[i].SCpnt)
- panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
- BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
-
- if (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED)
- printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
-
- return SCSI_ABORT_SNOOZE;
- }
-
- if (HD(j)->cp_stat[i] == IN_RESET) {
- printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
- return SCSI_ABORT_ERROR;
- }
-
- if (HD(j)->cp_stat[i] == LOCKED) {
- printk("%s: abort, mbox %d is locked.\n", BN(j), i);
- return SCSI_ABORT_NOT_RUNNING;
- }
-
- if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
- SCarg->result = DID_ABORT << 16;
- SCarg->host_scribble = NULL;
- HD(j)->cp_stat[i] = FREE;
- printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
- BN(j), i, SCarg->pid);
- SCarg->scsi_done(SCarg);
- return SCSI_ABORT_SUCCESS;
- }
-
- panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
-}
-
-int u14_34f_old_abort(Scsi_Cmnd *SCarg) {
- int rtn;
-
- rtn = do_old_abort(SCarg);
- return rtn;
-}
-
static inline int do_abort(Scsi_Cmnd *SCarg) {
unsigned int i, j;
return do_abort(SCarg);
}
-static inline int do_old_reset(Scsi_Cmnd *SCarg) {
- unsigned int i, j, time, k, c, limit = 0;
- int arg_done = FALSE;
- Scsi_Cmnd *SCpnt;
-
- j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
- printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
- BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
-
- if (SCarg->host_scribble == NULL)
- printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
-
- if (SCarg->serial_number_at_timeout &&
- (SCarg->serial_number != SCarg->serial_number_at_timeout)) {
- printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
- return SCSI_RESET_NOT_RUNNING;
- }
-
- if (HD(j)->in_reset) {
- printk("%s: reset, exit, already in reset.\n", BN(j));
- return SCSI_RESET_ERROR;
- }
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: reset, exit, timeout error.\n", BN(j));
- return SCSI_RESET_ERROR;
- }
-
- HD(j)->retries = 0;
-
- for (c = 0; c <= sh[j]->max_channel; c++)
- for (k = 0; k < sh[j]->max_id; k++) {
- HD(j)->target_redo[k][c] = TRUE;
- HD(j)->target_to[k][c] = 0;
- }
-
- for (i = 0; i < sh[j]->can_queue; i++) {
-
- if (HD(j)->cp_stat[i] == FREE) continue;
-
- if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
- continue;
- }
-
- if (!(SCpnt = HD(j)->cp[i].SCpnt))
- panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
-
- if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
- HD(j)->cp_stat[i] = ABORTING;
- printk("%s: reset, mbox %d aborting, pid %ld.\n",
- BN(j), i, SCpnt->pid);
- }
-
- else {
- HD(j)->cp_stat[i] = IN_RESET;
- printk("%s: reset, mbox %d in reset, pid %ld.\n",
- BN(j), i, SCpnt->pid);
- }
-
- if (SCpnt->host_scribble == NULL)
- panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
-
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
-
- if (SCpnt->scsi_done == NULL)
- panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
-
- if (SCpnt == SCarg) arg_done = TRUE;
- }
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: reset, cannot reset, timeout error.\n", BN(j));
- return SCSI_RESET_ERROR;
- }
-
- outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR);
- printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
-
-#if defined(DEBUG_RESET)
- do_trace = TRUE;
-#endif
-
- HD(j)->in_reset = TRUE;
- SPIN_UNLOCK
- time = jiffies;
- while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
- SPIN_LOCK
- printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
-
- for (i = 0; i < sh[j]->can_queue; i++) {
-
- if (HD(j)->cp_stat[i] == IN_RESET) {
- SCpnt = HD(j)->cp[i].SCpnt;
- SCpnt->result = DID_RESET << 16;
- SCpnt->host_scribble = NULL;
-
- /* This mailbox is still waiting for its interrupt */
- HD(j)->cp_stat[i] = LOCKED;
-
- printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
- }
-
- else if (HD(j)->cp_stat[i] == ABORTING) {
- SCpnt = HD(j)->cp[i].SCpnt;
- SCpnt->result = DID_RESET << 16;
- SCpnt->host_scribble = NULL;
-
- /* This mailbox was never queued to the adapter */
- HD(j)->cp_stat[i] = FREE;
-
- printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
- }
-
- else
-
- /* Any other mailbox has already been set free by interrupt */
- continue;
-
- SCpnt->scsi_done(SCpnt);
- }
-
- HD(j)->in_reset = FALSE;
- do_trace = FALSE;
-
- if (arg_done) {
- printk("%s: reset, exit, success.\n", BN(j));
- return SCSI_RESET_SUCCESS;
- }
- else {
- printk("%s: reset, exit, wakeup.\n", BN(j));
- return SCSI_RESET_PUNT;
- }
-}
-
-int u14_34f_old_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
- int rtn;
-
- rtn = do_old_reset(SCarg);
- return rtn;
-}
-
static inline int do_reset(Scsi_Cmnd *SCarg) {
unsigned int i, j, time, k, c, limit = 0;
int arg_done = FALSE;
if (link_statistics) {
if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
- batchcount++; readycount += n_ready, seeknosort += seek / 1024;
+ batchcount++; readycount += n_ready; seeknosort += seek / 1024;
if (input_only) inputcount++;
if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
else seeksorted += (iseek + maxsec - minsec) / 1024;
if (tstatus == GOOD)
HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
- if (spp->target_status && SCpnt->device->type == TYPE_DISK)
+ if (spp->target_status && SCpnt->device->type == TYPE_DISK &&
+ (!(tstatus == CHECK_CONDITION && HD(j)->iocount <= 1000 &&
+ (SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
"target_status 0x%x, sense key 0x%x.\n", BN(j),
SCpnt->channel, SCpnt->target, SCpnt->lun,
#include "scsi_module.c"
#ifndef MODULE
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-void u14_34f_setup(char *str, int *ints) {
- internal_setup(str, ints);
-}
-#else
__setup("u14-34f=", option_setup);
-#endif
-
#endif /* end MODULE */
#define _U14_34F_H
#include <scsi/scsicam.h>
-#include <linux/version.h>
int u14_34f_detect(Scsi_Host_Template *);
int u14_34f_release(struct Scsi_Host *);
int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int u14_34f_abort(Scsi_Cmnd *);
-int u14_34f_old_abort(Scsi_Cmnd *);
int u14_34f_reset(Scsi_Cmnd *);
-int u14_34f_old_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
-#define U14_34F_VERSION "5.11.00"
-
-#ifndef LinuxVersionCode
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-#endif
+#define U14_34F_VERSION "6.02.00"
#define ULTRASTOR_14_34F { \
name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
detect: u14_34f_detect, \
release: u14_34f_release, \
queuecommand: u14_34f_queuecommand, \
- abort: u14_34f_old_abort, \
- reset: u14_34f_old_reset, \
+ abort: NULL, \
+ reset: NULL, \
eh_abort_handler: u14_34f_abort, \
eh_device_reset_handler: NULL, \
eh_bus_reset_handler: NULL, \
/* This is what the 3393 chip looks like to us */
typedef struct {
volatile unsigned char SASR;
+#if !defined(CONFIG_MVME147_SCSI)
char pad;
+#endif
#ifdef CONFIG_SGI_IP22
char pad2,pad3;
#endif
void wd33c93_intr (struct Scsi_Host *instance);
int wd33c93_proc_info(char *, char **, off_t, int, int, int);
int wd33c93_reset (Scsi_Cmnd *, unsigned int);
+void wd33c93_release(void);
#endif /* WD33C93_H */
* Changes:
* 20000815 Updated driver to kernel 2.4, some cleanups/fixes
* Nils Faerber <nils@kernelconcepts.de>
+ *
+ * 20000909 Changed cs_read, cs_write and drain_dac
+ * Nils Faerber <nils@kernelconcepts.de>
+ *
* 20001110 Added __initdata to BA1Struct in cs461x_image.h
* and three more __init here
* Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ *
+ * 20001023 Ported to Linux 2.4 PCI interface, some cleanups
+ * Christoph Hellwig <hch@caldera.de>
+ *
*/
#include <linux/module.h>
#define GOF_PER_SEC 200
-/*
- * Define this to enable recording,
- * this is curently broken and using it will cause data corruption
- * in kernel- and user-space!
- */
-/* #define CS46XX_ENABLE_RECORD */
-
static int external_amp = 0;
static int thinkpad = 0;
-/* an instance of the 4610 channel */
+/* An instance of the 4610 channel */
struct cs_channel
{
void *state;
};
-#define DRIVER_VERSION "0.09"
+#define DRIVER_VERSION "0.14"
/* magic numbers to protect our data structures */
#define CS_CARD_MAGIC 0x46524F4D /* "FROM" */
unsigned int magic;
/* We keep cs461x cards in a linked list */
- struct cs_card *next;
+ struct list_head devs;
/* The cs461x has a certain amount of cross channel interaction
so we use a single per card lock */
void (*free_pcm_channel)(struct cs_card *, int chan);
};
-static struct cs_card *devs = NULL;
+static LIST_HEAD(devs);
static int cs_open_mixdev(struct inode *inode, struct file *file);
static int cs_release_mixdev(struct inode *inode, struct file *file);
tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
tmo >>= sample_shift[dmabuf->fmt];
- tmo += (4096*HZ)/dmabuf->rate;
+ tmo += (2048*HZ)/dmabuf->rate;
if (!schedule_timeout(tmo ? tmo : 1) && tmo){
printk(KERN_ERR "cs461x: drain_dac, dma timeout? %d\n", count);
memset (dmabuf->rawbuf + swptr, silence, clear_cnt);
dmabuf->endcleared = 1;
}
- }
- wake_up(&dmabuf->wait);
+ }
+ if (dmabuf->count < (signed)dmabuf->dmasize/2)
+ wake_up(&dmabuf->wait);
}
}
/* error handling and process wake up for DAC */
__stop_dac(state);
dmabuf->error++;
}
- wake_up(&dmabuf->wait);
+ if (dmabuf->count < (signed)dmabuf->dmasize/2)
+ wake_up(&dmabuf->wait);
}
}
}
memcpy(state->dmabuf.rawbuf + (2048*state->dmabuf.pringbuf++),
state->dmabuf.pbuf+2048*state->dmabuf.ppingbuf++, 2048);
state->dmabuf.ppingbuf&=1;
- if(state->dmabuf.pringbuf > (PAGE_SIZE<<state->dmabuf.buforder)/2048)
+ if(state->dmabuf.pringbuf >= (PAGE_SIZE<<state->dmabuf.buforder)/2048)
state->dmabuf.pringbuf=0;
cs_update_ptr(state);
}
{
struct cs_state *state = (struct cs_state *)file->private_data;
struct dmabuf *dmabuf = &state->dmabuf;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
unsigned long flags;
unsigned swptr;
return -EFAULT;
ret = 0;
+ add_wait_queue(&state->dmabuf.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&state->card->lock, flags);
if (dmabuf->count > (signed) dmabuf->dmasize) {
cnt = dmabuf->dmasize - swptr;
if (dmabuf->count < cnt)
cnt = dmabuf->count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&state->card->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
- unsigned long tmo;
/* buffer is empty, start the dma machine and wait for data to be
recorded */
start_adc(state);
if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- return ret;
- }
- /* This isnt strictly right for the 810 but it'll do */
- tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
- tmo >>= sample_shift[dmabuf->fmt];
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer overrun. And worse, there is
- NOTHING we can do to prevent it. */
- if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
-#ifdef DEBUG
- printk(KERN_ERR "cs461x: recording schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
-#endif
- /* a buffer overrun, we delay the recovery untill next time the
- while loop begin and we REALLY have space to record */
+ if (!ret)
+ ret = -EAGAIN;
+ remove_wait_queue(&state->dmabuf.wait, &wait);
+ break;
}
+ schedule();
if (signal_pending(current)) {
ret = ret ? ret : -ERESTARTSYS;
- return ret;
+ break;
}
continue;
}
if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
- if (!ret) ret = -EFAULT;
- return ret;
+ if (!ret)
+ ret = -EFAULT;
+ break;
}
swptr = (swptr + cnt) % dmabuf->dmasize;
ret += cnt;
start_adc(state);
}
+ remove_wait_queue(&state->dmabuf.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
{
struct cs_state *state = (struct cs_state *)file->private_data;
struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t ret = 0;
unsigned long flags;
unsigned swptr;
int cnt;
return ret;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
- ret = 0;
+ add_wait_queue(&state->dmabuf.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&state->card->lock, flags);
if (dmabuf->count < 0) {
cnt = dmabuf->dmasize - swptr;
if (dmabuf->count + cnt > dmabuf->dmasize)
cnt = dmabuf->dmasize - dmabuf->count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&state->card->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
- unsigned long tmo;
/* buffer is full, start the dma machine and wait for data to be
played */
start_dac(state);
if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- return ret;
- }
- /* Not strictly correct but works */
- tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
- tmo >>= sample_shift[dmabuf->fmt];
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer underrun. And worse, there is
- NOTHING we can do to prevent it. */
- if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
-#ifdef DEBUG
- printk(KERN_ERR "cs461x: playback schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
-#endif
- /* a buffer underrun, we delay the recovery untill next time the
- while loop begin and we REALLY have data to play */
+ if (!ret)
+ ret = -EAGAIN;
+ remove_wait_queue(&state->dmabuf.wait, &wait);
+ break;
}
+ schedule();
if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- return ret;
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
}
continue;
}
if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
- if (!ret) ret = -EFAULT;
- return ret;
+ if (!ret)
+ ret = -EFAULT;
+ break;
}
swptr = (swptr + cnt) % dmabuf->dmasize;
return mask;
}
+
+/*
+ * We let users mmap the ring buffer. Its not the real DMA buffer but
+ * that side of the code is hidden in the IRQ handling. We do a software
+ * emulation of DMA from a 64K or so buffer into a 2K FIFO.
+ * (the hardware probably deserves a moan here but Crystal send me nice
+ * toys ;)).
+ */
+
static int cs_mmap(struct file *file, struct vm_area_struct *vma)
{
- return -EINVAL;
-#if 0
struct cs_state *state = (struct cs_state *)file->private_data;
struct dmabuf *dmabuf = &state->dmabuf;
int ret;
} else
return -EINVAL;
- if (vma->vm_offset != 0)
+ if (vma->vm_pgoff != 0)
return -EINVAL;
size = vma->vm_end - vma->vm_start;
if (size > (PAGE_SIZE << dmabuf->buforder))
dmabuf->mapped = 1;
return 0;
-#endif
}
static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
static void amp_voyetra(struct cs_card *card, int change)
{
- /* Manage the EAPD bit on the Crystal 4297 */
+ /* Manage the EAPD bit on the Crystal 4297 and the Analog AD1885 */
int old=card->amplifier;
card->amplifier+=change;
}
-
/*
* Untested
*/
static void amp_voyetra_4294(struct cs_card *card, int change)
{
struct ac97_codec *c=card->ac97_codec[0];
- int old = card->amplifier;
card->amplifier+=change;
static int cs_open(struct inode *inode, struct file *file)
{
int i = 0;
- struct cs_card *card = devs;
+ struct cs_card *card;
struct cs_state *state = NULL;
struct dmabuf *dmabuf = NULL;
+ struct list_head *list;
#ifndef CS46XX_ENABLE_RECORD
if (file->f_mode & FMODE_READ)
return -ENODEV;
#endif
- /* find an avaiable virtual channel (instance of /dev/dsp) */
- while (card != NULL) {
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ card = list_entry(list, struct cs_card, devs);
for (i = 0; i < NR_HW_CH; i++) {
if (card->states[i] == NULL) {
state = card->states[i] = (struct cs_state *)
goto found_virt;
}
}
- card = card->next;
}
/* no more virtual channel avaiable */
if (!state)
{
struct cs_card *card = dev->private_data;
int count;
+ int val2;
+ if (reg == AC97_CD_VOL)
+ val2 = cs_ac97_get(dev, AC97_CD_VOL);
+
/*
* 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
* 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
*/
if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)
printk(KERN_WARNING "cs461x: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val);
+
+ /*
+ * Adjust power if the mixer is selected/deselected according
+ * to the CD.
+ *
+ * IF the CD is a valid input source (mixer or direct) AND
+ * the CD is not muted THEN power is needed
+ *
+ * We do two things. When record select changes the input to
+ * add/remove the CD we adjust the power count if the CD is
+ * unmuted.
+ *
+ * When the CD mute changes we adjust the power level if the
+ * CD was a valid input.
+ *
+ * We also check for CD volume != 0, as the CD mute isn't
+ * normally tweaked from userspace.
+ */
+
+ /* CD mute change ? */
+ if (reg == AC97_CD_VOL) {
+ /* Mute bit change ? */
+ if ((val2^val) & 0x8000 || ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val)) {
+ /* This is a hack but its cleaner than the alternatives.
+ Right now card->ac97_codec[0] might be NULL as we are
+ still doing codec setup. This does an early assignment
+ to avoid the problem if it occurs */
+
+ if (card->ac97_codec[0] == NULL)
+ card->ac97_codec[0] = dev;
+
+ /* Mute on */
+ if(val & 0x8000 || val == 0x1f1f)
+ card->amplifier_ctrl(card, -1);
+ else /* Mute off power on */
+ card->amplifier_ctrl(card, 1);
+ }
+ }
}
{
int i;
int minor = MINOR(inode->i_rdev);
- struct cs_card *card = devs;
+ struct cs_card *card;
+ struct list_head *list;
- for (card = devs; card != NULL; card = card->next)
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ card = list_entry(list, struct cs_card, devs);
for (i = 0; i < NR_AC97; i++)
if (card->ac97_codec[i] != NULL &&
card->ac97_codec[i]->dev_mixer == minor)
goto match;
+ }
+
if (!card)
return -ENODEV;
file->private_data = card->ac97_codec[i];
card->active_ctrl(card,1);
- MOD_INC_USE_COUNT;
return 0;
}
static int cs_release_mixdev(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
- struct cs_card *card = devs;
+ struct cs_card *card;
+ struct list_head *list;
int i;
-
- for (card = devs; card != NULL; card = card->next)
+
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ card = list_entry(list, struct cs_card, devs);
for (i = 0; i < NR_AC97; i++)
if (card->ac97_codec[i] != NULL &&
card->ac97_codec[i]->dev_mixer == minor)
goto match;
+ }
if (!card)
return -ENODEV;
match:
card->active_ctrl(card, -1);
- MOD_DEC_USE_COUNT;
return 0;
}
* for a reset.
*/
cs461x_pokeBA0(card, BA0_ACCTL, 0);
- udelay(500);
+ udelay(50);
cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN);
/*
* generating bit clock (so we don't try to start the PLL without an
* input clock).
*/
- mdelay(10); /* 1 should be enough ?? */
+ mdelay(5); /* 1 should be enough ?? */
/*
* Set the serial port timing configuration, so that
/*
* Wait until the PLL has stabilized.
*/
- mdelay(100); /* Again 1 should be enough ?? */
+ mdelay(5); /* Again 1 should be enough ?? */
/*
* Turn on clocking of the core so that we can setup the serial ports.
* Card subid table
*/
-struct cs_card_type
-{
+struct cs_card_type {
u16 vendor;
u16 id;
char *name;
void (*active)(struct cs_card *, int);
};
-static struct cs_card_type __initdata cards[]={
+static struct cs_card_type __devinitdata cards[]={
{0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL},
{0x5053, 0x3357, "Voyetra", amp_voyetra, NULL},
/* MI6020/21 use the same chipset as the Thinkpads, maybe needed */
{PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack},
{PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack},
{PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL},
+ {0, 0, "Card without SSID set", NULL, NULL },
{0, 0, NULL, NULL, NULL}
};
-static int __init cs_install(struct pci_dev *pci_dev)
+static int __devinit cs_probe(struct pci_dev * pci_dev, const struct pci_device_id * id)
{
struct cs_card *card;
struct cs_card_type *cp = &cards[0];
- u16 ss_card, ss_vendor;
-
-
- pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
- pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "cs461x: out of memory\n");
}
memset(card, 0, sizeof(*card));
- card->ba0_addr = pci_dev->resource[0].start&PCI_BASE_ADDRESS_MEM_MASK;
- card->ba1_addr = pci_dev->resource[1].start&PCI_BASE_ADDRESS_MEM_MASK;
+ card->ba0_addr = pci_resource_start(pci_dev, 0);
+ card->ba1_addr = pci_resource_start(pci_dev, 1);
card->pci_dev = pci_dev;
card->irq = pci_dev->irq;
card->magic = CS_CARD_MAGIC;
while(cp->name)
{
- if(cp->vendor == ss_vendor && cp->id == ss_card)
+ if(cp->vendor == id->subvendor && cp->id == id->subdevice)
{
card->amplifier_ctrl = cp->amp;
if(cp->active)
if(cp->name==NULL)
{
printk(KERN_INFO "cs461x: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
- ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
+ id->subvendor, id->subdevice, card->ba0_addr, card->ba1_addr, card->irq);
}
else
{
unregister_sound_dsp(card->dev_audio);
goto fail;
}
- card->next = devs;
- devs = card;
-
+
+ pci_set_drvdata (pci_dev, card);
+
+ list_add_tail(&card->devs, &devs);
+
card->active_ctrl(card, -1);
return 0;
}
-static void cs_remove(struct cs_card *card)
+static void __devexit cs_remove(struct pci_dev * pci_dev)
{
+ struct cs_card * card = pci_get_drvdata (pci_dev);
int i;
unsigned int tmp;
-
+
+ list_del(&card->devs);
card->active_ctrl(card,1);
tmp = cs461x_peek(card, BA1_PFIE);
MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela");
MODULE_DESCRIPTION("Crystal SoundFusion Audio Support");
+MODULE_PARM(external_amp, "i");
+MODULE_PARM(thinkpad, "i");
+
+static struct pci_device_id cs_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CIRRUS, 0x6004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, }
+};
+MODULE_DEVICE_TABLE (pci, cs_pci_tbl);
+
+static struct pci_driver cs_pci_driver = {
+ name: "cs46xx",
+ id_table: cs_pci_tbl,
+ probe: cs_probe,
+ remove: cs_remove,
+};
-int __init cs_probe(void)
+static int __init cs_init(void)
{
- struct pci_dev *pcidev = NULL;
int foundone=0;
- if (!pci_present()) /* No PCI bus in this machine! */
- return -ENODEV;
-
printk(KERN_INFO "Crystal 4280/461x + AC97 Audio, version "
DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
- while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6001 , pcidev))!=NULL ) {
- if (cs_install(pcidev)==0)
- foundone++;
- }
- while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6003 , pcidev))!=NULL ) {
- if (cs_install(pcidev)==0)
- foundone++;
- }
- while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6004 , pcidev))!=NULL ) {
- if (cs_install(pcidev)==0)
- foundone++;
- }
-
- printk(KERN_INFO "cs461x: Found %d audio device(s).\n",
- foundone);
- return foundone;
+ return pci_module_init(&cs_pci_driver);
}
-#ifdef MODULE
-
-int init_module(void)
+static void __exit cs_exit(void)
{
- if(cs_probe()==0)
- printk(KERN_ERR "cs461x: No devices found.\n");
- return 0;
+ pci_unregister_driver(&cs_pci_driver);
}
-void cleanup_module (void)
-{
- struct cs_card *next;
- while(devs)
- {
- next=devs->next;
- cs_remove(devs);
- devs=next;
- }
-}
+module_init(cs_init);
+module_exit(cs_exit);
-MODULE_PARM(external_amp, "i");
-MODULE_PARM(thinkpad, "i");
-
-#endif
static void *AtaAlloc(unsigned int size, int flags)
{
- return atari_stram_alloc( size, NULL, "dmasound" );
+ return atari_stram_alloc(size, "dmasound");
}
static void AtaFree(void *obj, unsigned int size)
/*
* The minimum period for audio depends on htotal (for OCS/ECS/AGA)
* (Imported from arch/m68k/amiga/amisound.c)
- *
- * FIXME: if amifb is not used, there should be a method to change htotal
*/
extern volatile u_short amiga_audio_min_period;
static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg)
{
int i, val=0;
+ unsigned long flags;
VALIDATE_CARD(card);
if (cmd == SOUND_MIXER_INFO) {
if(!card->mix.recmask_io) {
val = 0;
} else {
- spin_lock(&card->lock);
+ spin_lock_irqsave(&card->lock, flags);
val = card->mix.recmask_io(card,1,0);
- spin_unlock(&card->lock);
+ spin_unlock_irqrestore(&card->lock, flags);
}
break;
return -EINVAL;
/* do we ever want to touch the hardware? */
-/* spin_lock(&card->lock);
+/* spin_lock_irqsave(&card->lock, flags);
val = card->mix.read_mixer(card,i);
- spin_unlock(&card->lock);*/
+ spin_unlock_irqrestore(&card->lock, flags);*/
val = card->mix.mixer_state[i];
/* M_printk("returned 0x%x for mixer %d\n",val,i);*/
if(!val) return 0;
if(! (val &= card->mix.record_sources)) return -EINVAL;
- spin_lock(&card->lock);
+ spin_lock_irqsave(&card->lock, flags);
card->mix.recmask_io(card,0,val);
- spin_unlock(&card->lock);
+ spin_unlock_irqrestore(&card->lock, flags);
return 0;
default:
if ( ! supported_mixer(card,i))
return -EINVAL;
- spin_lock(&card->lock);
+ spin_lock_irqsave(&card->lock, flags);
set_mixer(card,i,val);
- spin_unlock(&card->lock);
+ spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
ess = &card->channels[0];
+ if (pci_enable_device(pcidev)) {
+ printk (KERN_ERR "maestro: pci_enable_device() failed\n");
+ for (i = 0; i < NR_DSPS; i++) {
+ struct ess_state *s = &card->channels[i];
+ if (s->dev_audio != -1)
+ unregister_sound_dsp(s->dev_audio);
+ }
+ release_region(card->iobase, 256);
+ unregister_reboot_notifier(&maestro_nb);
+ kfree(card);
+ return 0;
+ }
+
/*
* Ok card ready. Begin setup proper
*/
fi
dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
-comment 'USB Devices'
- dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
- dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
- fi
+ comment 'USB Device Class drivers'
dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
- dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
- dep_tristate ' USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
- if [ "$CONFIG_USB_SERIAL" != "n" ]; then
- bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC
- dep_tristate ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
- dep_tristate ' USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
- if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
- dep_tristate ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL
- dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL
- dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL
- dep_tristate ' USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL
- if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then
- bool ' USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28
- bool ' USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X
- bool ' USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
- bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
- bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
- fi
- dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL
- dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
- fi
- bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
- fi
- dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
- dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
- dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB
- fi
+ dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
if [ "$CONFIG_USB_STORAGE" != "n" ]; then
bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
+ bool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM
fi
- dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
- dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET
- dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET
- dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB
- dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV
- dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
- dep_tristate ' NetChip 1080-based USB Host-to-Host Link (EXPERIMENTAL)' CONFIG_USB_NET1080 $CONFIG_USB $CONFIG_NET
- fi
+ dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
+ dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
comment 'USB Human Interface Devices (HID)'
if [ "$CONFIG_INPUT" = "n" ]; then
fi
dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
fi
+
+ comment 'USB Imaging devices'
+ dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
+ dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
+ dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
+
+ comment 'USB Multimedia devices'
+ dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
+ dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
+
+ comment 'USB Network adaptors'
+ dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+ dep_tristate ' NetChip 1080-based USB Host-to-Host Link (EXPERIMENTAL)' CONFIG_USB_NET1080 $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+
+ comment 'USB port drivers'
+ dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
+ source drivers/usb/serial/Config.in
+
+ comment 'USB misc drivers'
+ dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
fi
endmenu
--- /dev/null
+#
+# USB Serial device configuration
+#
+mainmenu_option next_comment
+comment 'USB Serial Converter support'
+
+tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
+if [ "$CONFIG_USB_SERIAL" != "n" ]; then
+ bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
+ bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC
+ dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
+ dep_tristate ' USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+ dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+ if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then
+ bool ' USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28
+ bool ' USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X
+ bool ' USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
+ bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
+ bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
+ fi
+ dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+fi
+
+endmenu
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
# Objects that export symbols.
export-objs := usbserial.o
--- /dev/null
+/*
+ * USB Empeg empeg-car player driver
+ *
+ * Copyright (C) 2000
+ * Gary Brubaker (xavyer@ix.netcom.com)
+ *
+ * Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * 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, version 2.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (11/13/2000) gb
+ * Moved tty->low_latency = 1 from empeg_read_bulk_callback() to empeg_open()
+ * (It only needs to be set once - Doh!)
+ *
+ * (11/11/2000) gb
+ * Updated to work with id_table structure.
+ *
+ * (11/04/2000) gb
+ * Forked this from visor.c, and hacked it up to work with an
+ * Empeg ltd. empeg-car player. Constructive criticism welcomed.
+ * I would like to say, 'Thank You' to Greg Kroah-Hartman for the
+ * use of his code, and for his guidance, advice and patience. :)
+ * A 'Thank You' is in order for John Ripley of Empeg ltd for his
+ * advice, and patience too.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#define EMPEG_VENDOR_ID 0x084f
+#define EMPEG_PRODUCT_ID 0x0001
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+/* function prototypes for an empeg-car player */
+static int empeg_open (struct usb_serial_port *port, struct file *filp);
+static void empeg_close (struct usb_serial_port *port, struct file *filp);
+static int empeg_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static void empeg_throttle (struct usb_serial_port *port);
+static void empeg_unthrottle (struct usb_serial_port *port);
+static int empeg_startup (struct usb_serial *serial);
+static void empeg_shutdown (struct usb_serial *serial);
+static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void empeg_write_bulk_callback (struct urb *urb);
+static void empeg_read_bulk_callback (struct urb *urb);
+
+static __devinitdata struct usb_device_id id_table [] = {
+ { idVendor: EMPEG_VENDOR_ID, idProduct: EMPEG_PRODUCT_ID },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct usb_serial_device_type empeg_device = {
+ name: "Empeg",
+ id_table: id_table,
+ needs_interrupt_in: MUST_HAVE_NOT, /* must not have an interrupt in endpoint */
+ needs_bulk_in: MUST_HAVE, /* must have a bulk in endpoint */
+ needs_bulk_out: MUST_HAVE, /* must have a bulk out endpoint */
+ num_interrupt_in: 0,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: empeg_open,
+ close: empeg_close,
+ throttle: empeg_throttle,
+ unthrottle: empeg_unthrottle,
+ startup: empeg_startup,
+ shutdown: empeg_shutdown,
+ ioctl: empeg_ioctl,
+ set_termios: empeg_set_termios,
+ write: empeg_write,
+ write_bulk_callback: empeg_write_bulk_callback,
+ read_bulk_callback: empeg_read_bulk_callback,
+};
+
+#define NUM_URBS 16
+#define URB_TRANSFER_BUFFER_SIZE 4096
+
+static struct urb *write_urb_pool[NUM_URBS];
+static spinlock_t write_urb_pool_lock;
+static int bytes_in;
+static int bytes_out;
+
+/******************************************************************************
+ * Empeg specific driver functions
+ ******************************************************************************/
+static int empeg_open (struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ unsigned long flags;
+ int result;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return -ENODEV;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ ++port->open_count;
+ MOD_INC_USE_COUNT;
+
+ /* gb - 2000/11/05
+ *
+ * personally, I think these termios should be set in
+ * empeg_startup(), but it appears doing so leads to one
+ * of those chicken/egg problems. :)
+ *
+ */
+ port->tty->termios->c_iflag
+ &= ~(IGNBRK
+ | BRKINT
+ | PARMRK
+ | ISTRIP
+ | INLCR
+ | IGNCR
+ | ICRNL
+ | IXON);
+
+ port->tty->termios->c_oflag
+ &= ~OPOST;
+
+ port->tty->termios->c_lflag
+ &= ~(ECHO
+ | ECHONL
+ | ICANON
+ | ISIG
+ | IEXTEN);
+
+ port->tty->termios->c_cflag
+ &= ~(CSIZE
+ | PARENB);
+
+ port->tty->termios->c_cflag
+ |= CS8;
+
+ /* gb - 2000/11/05
+ *
+ * force low_latency on
+ *
+ * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
+ * force the data through if low_latency is set. Otherwise the pushes are
+ * scheduled; this is bad as it opens up the possibility of dropping bytes
+ * on the floor. We are trying to sustain high data transfer rates; and
+ * don't want to drop bytes on the floor.
+ * Moral: use low_latency - drop no bytes - life is good. :)
+ *
+ */
+ port->tty->low_latency = 1;
+
+ if (!port->active) {
+ port->active = 1;
+ bytes_in = 0;
+ bytes_out = 0;
+
+ /* Start reading from the device */
+ FILL_BULK_URB(
+ port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ empeg_read_bulk_callback,
+ port);
+
+ port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+ result = usb_submit_urb(port->read_urb);
+
+ if (result)
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return 0;
+}
+
+
+static void empeg_close (struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial;
+ unsigned char *transfer_buffer;
+ unsigned long flags;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ serial = get_usb_serial (port, __FUNCTION__);
+ if (!serial)
+ return;
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ --port->open_count;
+ MOD_DEC_USE_COUNT;
+
+ if (port->open_count <= 0) {
+ transfer_buffer = kmalloc (0x12, GFP_KERNEL);
+
+ if (!transfer_buffer) {
+ err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
+ } else {
+ kfree (transfer_buffer);
+ }
+
+ /* shutdown our bulk read */
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+ port->open_count = 0;
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ /* Uncomment the following line if you want to see some statistics in your syslog */
+ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */
+
+}
+
+
+static int empeg_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+ struct urb *urb;
+ const unsigned char *current_position = buf;
+ unsigned long flags;
+ int status;
+ int i;
+ int bytes_sent = 0;
+ int transfer_size;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf);
+
+ while (count > 0) {
+
+ /* try to find a free urb in our list of them */
+ urb = NULL;
+
+ spin_lock_irqsave (&write_urb_pool_lock, flags);
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (write_urb_pool[i]->status != -EINPROGRESS) {
+ urb = write_urb_pool[i];
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore (&write_urb_pool_lock, flags);
+
+ if (urb == NULL) {
+ dbg (__FUNCTION__ " - no more free urbs");
+ goto exit;
+ }
+
+ if (urb->transfer_buffer == NULL) {
+ urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (urb->transfer_buffer == NULL) {
+ err(__FUNCTION__" no more kernel memory...");
+ goto exit;
+ }
+ }
+
+ transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE);
+
+ if (from_user) {
+ copy_from_user (urb->transfer_buffer, current_position, transfer_size);
+ } else {
+ memcpy (urb->transfer_buffer, current_position, transfer_size);
+ }
+
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+ /* build up our urb */
+ FILL_BULK_URB (
+ urb,
+ serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ urb->transfer_buffer,
+ transfer_size,
+ empeg_write_bulk_callback,
+ port);
+
+ urb->transfer_flags |= USB_QUEUE_BULK;
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb);
+ if (status)
+ dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+
+ current_position += transfer_size;
+ bytes_sent += transfer_size;
+ count -= transfer_size;
+ bytes_out += transfer_size;
+
+ }
+
+exit:
+ return bytes_sent;
+
+}
+
+
+static void empeg_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (urb->status) {
+ dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+ return;
+ }
+
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ return;
+
+}
+
+
+static void empeg_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int i;
+ int result;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
+ return;
+ }
+
+ if (urb->status) {
+ dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+ tty = port->tty;
+
+ if (urb->actual_length) {
+ for (i = 0; i < urb->actual_length ; ++i) {
+ /* gb - 2000/11/13
+ * If we insert too many characters we'll overflow the buffer.
+ * This means we'll lose bytes - Decidedly bad.
+ */
+ if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ tty_flip_buffer_push(tty);
+ }
+ /* gb - 2000/11/13
+ * This doesn't push the data through unless tty->low_latency is set.
+ */
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ /* gb - 2000/11/13
+ * Goes straight through instead of scheduling - if tty->low_latency is set.
+ */
+ tty_flip_buffer_push(tty);
+ bytes_in += urb->actual_length;
+ }
+
+ /* Continue trying to always read */
+ FILL_BULK_URB(
+ port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ empeg_read_bulk_callback,
+ port);
+
+ port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+ result = usb_submit_urb(port->read_urb);
+
+ if (result)
+ err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+
+ return;
+
+}
+
+
+static void empeg_throttle (struct usb_serial_port *port)
+{
+ unsigned long flags;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ usb_unlink_urb (port->read_urb);
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return;
+
+}
+
+
+static void empeg_unthrottle (struct usb_serial_port *port)
+{
+ unsigned long flags;
+ int result;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ port->read_urb->dev = port->serial->dev;
+
+ result = usb_submit_urb(port->read_urb);
+
+ if (result)
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return;
+
+}
+
+
+static int empeg_startup (struct usb_serial *serial)
+{
+
+ dbg(__FUNCTION__);
+
+ dbg(__FUNCTION__ " - Set config to 1");
+ usb_set_configuration (serial->dev, 1);
+
+ /* continue on with initialization */
+ return 0;
+
+}
+
+
+static void empeg_shutdown (struct usb_serial *serial)
+{
+ int i;
+
+ dbg (__FUNCTION__);
+
+ /* stop reads and writes on all ports */
+ for (i=0; i < serial->num_ports; ++i) {
+ while (serial->port[i].open_count > 0) {
+ empeg_close (&serial->port[i], NULL);
+ }
+ }
+
+}
+
+
+static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+
+ return -ENOIOCTLCMD;
+}
+
+
+/* This function is all nice and good, but we don't change anything based on it :) */
+static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+ unsigned int cflag = port->tty->termios->c_cflag;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg(__FUNCTION__ " - nothing to change...");
+ return;
+ }
+ }
+
+ if ((!port->tty) || (!port->tty->termios)) {
+ dbg(__FUNCTION__" - no tty structures");
+ return;
+ }
+
+ /* get the byte size */
+ switch (cflag & CSIZE) {
+ case CS5: dbg(__FUNCTION__ " - data bits = 5"); break;
+ case CS6: dbg(__FUNCTION__ " - data bits = 6"); break;
+ case CS7: dbg(__FUNCTION__ " - data bits = 7"); break;
+ default:
+ case CS8: dbg(__FUNCTION__ " - data bits = 8"); break;
+ }
+
+ /* determine the parity */
+ if (cflag & PARENB)
+ if (cflag & PARODD)
+ dbg(__FUNCTION__ " - parity = odd");
+ else
+ dbg(__FUNCTION__ " - parity = even");
+ else
+ dbg(__FUNCTION__ " - parity = none");
+
+ /* figure out the stop bits requested */
+ if (cflag & CSTOPB)
+ dbg(__FUNCTION__ " - stop bits = 2");
+ else
+ dbg(__FUNCTION__ " - stop bits = 1");
+
+ /* figure out the flow control settings */
+ if (cflag & CRTSCTS)
+ dbg(__FUNCTION__ " - RTS/CTS is enabled");
+ else
+ dbg(__FUNCTION__ " - RTS/CTS is disabled");
+
+ /* determine software flow control */
+ if (I_IXOFF(port->tty))
+ dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty));
+ else
+ dbg(__FUNCTION__ " - XON/XOFF is disabled");
+
+ /* get the baud rate wanted */
+ dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty));
+
+ return;
+
+}
+
+
+static int __init empeg_init (void)
+{
+ struct urb *urb;
+ int i;
+
+ usb_serial_register (&empeg_device);
+
+ /* create our write urb pool and transfer buffers */
+ spin_lock_init (&write_urb_pool_lock);
+ for (i = 0; i < NUM_URBS; ++i) {
+ urb = usb_alloc_urb(0);
+ write_urb_pool[i] = urb;
+ if (urb == NULL) {
+ err("No more urbs???");
+ continue;
+ }
+
+ urb->transfer_buffer = NULL;
+ urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err (__FUNCTION__ " - out of memory for urb buffers.");
+ continue;
+ }
+ }
+
+ return 0;
+
+}
+
+
+static void __exit empeg_exit (void)
+{
+ int i;
+ unsigned long flags;
+
+ usb_serial_deregister (&empeg_device);
+
+ spin_lock_irqsave (&write_urb_pool_lock, flags);
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (write_urb_pool[i]) {
+ /* FIXME - uncomment the following usb_unlink_urb call when
+ * the host controllers get fixed to set urb->dev = NULL after
+ * the urb is finished. Otherwise this call oopses. */
+ /* usb_unlink_urb(write_urb_pool[i]); */
+ if (write_urb_pool[i]->transfer_buffer)
+ kfree(write_urb_pool[i]->transfer_buffer);
+ usb_free_urb (write_urb_pool[i]);
+ }
+ }
+
+ spin_unlock_irqrestore (&write_urb_pool_lock, flags);
+
+}
+
+
+module_init(empeg_init);
+module_exit(empeg_exit);
+
+MODULE_AUTHOR("Gary Brubaker <xavyer@ix.netcom.com>");
+MODULE_DESCRIPTION("USB Empeg Mark I/II Driver");
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (11/12/2000) gkh
+ * Fixed bug with data being dropped on the floor by forcing tty->low_latency
+ * to be on. Hopefully this fixes the OHCI issue!
+ *
* (11/01/2000) Adam J. Richter
* usb_device_id table support
*
bytes_in = 0;
bytes_out = 0;
+ /* force low_latency on so that our tty_push actually forces the data through,
+ otherwise it is scheduled, and with high data rates (like with OHCI) data
+ can get lost. */
+ port->tty->low_latency = 1;
+
/* Start reading from the device */
FILL_BULK_URB(port->read_urb, serial->dev,
usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
tty = port->tty;
if (urb->actual_length) {
for (i = 0; i < urb->actual_length ; ++i) {
+ /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+ if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ tty_flip_buffer_push(tty);
+ }
+ /* this doesn't actually push the data through unless tty->low_latency is set */
tty_insert_flip_char(tty, data[i], 0);
}
tty_flip_buffer_push(tty);
* (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
* (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
* (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
#include "uhci-debug.h"
#include <linux/pm.h>
-static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);
static int debug = 1;
MODULE_PARM(debug, "i");
static kmem_cache_t *uhci_qh_cachep;
static kmem_cache_t *uhci_up_cachep; /* urb_priv */
-static LIST_HEAD(uhci_list);
-
static int rh_submit_urb(struct urb *urb);
static int rh_unlink_urb(struct urb *urb);
static int uhci_get_current_frame_number(struct usb_device *dev);
uhci = alloc_uhci(io_addr, io_size);
if (!uhci)
return -ENOMEM;
-
- INIT_LIST_HEAD(&uhci->uhci_list);
- list_add(&uhci->uhci_list, &uhci_list);
+ dev->driver_data = uhci;
request_region(uhci->io_addr, io_size, "usb-uhci");
if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) {
uhci->irq = irq;
- if (!uhci_start_root_hub(uhci)) {
- struct pm_dev *pmdev;
-
- pmdev = pm_register(PM_PCI_DEV,
- PM_PCI_ID(dev),
- handle_pm_event);
- if (pmdev)
- pmdev->data = uhci;
+ if (!uhci_start_root_hub(uhci))
return 0;
- }
}
/* Couldn't allocate IRQ if we got here */
- list_del(&uhci->uhci_list);
- INIT_LIST_HEAD(&uhci->uhci_list);
reset_hc(uhci);
release_region(uhci->io_addr, uhci->io_size);
return retval;
}
-static int found_uhci(struct pci_dev *dev)
+static int __devinit
+uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
int i;
pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
if (pci_enable_device(dev) < 0)
- return -1;
+ return -ENODEV;
if (!dev->irq) {
err("found UHCI device with no IRQ assigned. check BIOS settings!");
- return -1;
+ return -ENODEV;
}
/* Search for the IO base address.. */
return setup_uhci(dev, dev->irq, io_addr, io_size);
}
- return -1;
+ return -ENODEV;
}
-static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
+static void __devexit
+uhci_pci_remove (struct pci_dev *dev)
{
- struct uhci *uhci = dev->data;
- switch (rqst) {
- case PM_SUSPEND:
- reset_hc(uhci);
- break;
- case PM_RESUME:
- reset_hc(uhci);
- start_hc(uhci);
- break;
- }
- return 0;
+ struct uhci *uhci = dev->driver_data;
+
+ if (uhci->bus->root_hub)
+ usb_disconnect(&uhci->bus->root_hub);
+
+ usb_deregister_bus(uhci->bus);
+
+ reset_hc(uhci);
+ release_region(uhci->io_addr, uhci->io_size);
+
+ uhci_free_pending_qhs(uhci);
+
+ release_uhci(uhci);
+}
+
+static void
+uhci_pci_suspend (struct pci_dev *dev)
+{
+ reset_hc((struct uhci *) dev->driver_data);
}
-static int __init uhci_init(void)
+static void
+uhci_pci_resume (struct pci_dev *dev)
+{
+ reset_hc((struct uhci *) dev->driver_data);
+ start_hc((struct uhci *) dev->driver_data);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct pci_device_id __devinitdata uhci_pci_ids [] = { {
+
+ /* handle any USB UHCI controller */
+ class: ((PCI_CLASS_SERIAL_USB << 8) | 0x00),
+ class_mask: ~0,
+
+ /* no matter who makes it */
+ vendor: PCI_ANY_ID,
+ device: PCI_ANY_ID,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+
+ }, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE (pci, uhci_pci_ids);
+
+static struct pci_driver uhci_pci_driver = {
+ name: "usb-uhci",
+ id_table: &uhci_pci_ids [0],
+
+ probe: uhci_pci_probe,
+ remove: uhci_pci_remove,
+
+#ifdef CONFIG_PM
+ suspend: uhci_pci_suspend,
+ resume: uhci_pci_resume,
+#endif /* PM */
+};
+
+
+static int __init uhci_hcd_init(void)
{
int retval;
- struct pci_dev *dev;
- u8 type;
retval = -ENOMEM;
if (!uhci_up_cachep)
goto up_failed;
- retval = -ENODEV;
- dev = NULL;
- for (;;) {
- dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev);
- if (!dev)
- break;
-
- /* Is it the UHCI programming interface? */
- pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
- if (type != 0)
- continue;
-
- /* Ok set it up */
- retval = found_uhci(dev);
- }
-
- /* We only want to return an error code if ther was an error */
- /* and we didn't find a UHCI controller */
- if (retval && list_empty(&uhci_list))
+ retval = pci_module_init (&uhci_pci_driver);
+ if (retval)
goto init_failed;
return 0;
return retval;
}
-void uhci_cleanup(void)
+static void __exit uhci_hcd_cleanup (void)
{
- struct list_head *tmp, *head = &uhci_list;
-
- tmp = head->next;
- while (tmp != head) {
- struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list);
-
- tmp = tmp->next;
-
- list_del(&uhci->uhci_list);
- INIT_LIST_HEAD(&uhci->uhci_list);
-
- if (uhci->bus->root_hub)
- usb_disconnect(&uhci->bus->root_hub);
-
- usb_deregister_bus(uhci->bus);
-
- reset_hc(uhci);
- release_region(uhci->io_addr, uhci->io_size);
-
- uhci_free_pending_qhs(uhci);
-
- release_uhci(uhci);
- }
-
+ pci_unregister_driver (&uhci_pci_driver);
+
if (kmem_cache_destroy(uhci_up_cachep))
printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
printk(KERN_INFO "uhci: not all TD's were freed\n");
}
-static void __exit uhci_exit(void)
-{
- pm_unregister_all(handle_pm_event);
- uhci_cleanup();
-}
-
-module_init(uhci_init);
-module_exit(uhci_exit);
+module_init(uhci_hcd_init);
+module_exit(uhci_hcd_cleanup);
MODULE_AUTHOR("Linus Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber");
MODULE_DESCRIPTION("USB Universal Host Controller Interface driver");
else
dev->bus->bandwidth_int_reqs++;
urb->bandwidth = bustime;
-
+
+#ifdef USB_BANDWIDTH_MESSAGES
dbg("bandwidth alloc increased by %d to %d for %d requesters",
bustime,
dev->bus->bandwidth_allocated,
dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+#endif
}
/*
else
dev->bus->bandwidth_int_reqs--;
+#ifdef USB_BANDWIDTH_MESSAGES
dbg("bandwidth alloc reduced by %d to %d for %d requesters",
urb->bandwidth,
dev->bus->bandwidth_allocated,
dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+#endif
urb->bandwidth = 0;
}
usb_unlink_urb(&wacom->irq);
}
-static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
+static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
{
struct usb_endpoint_descriptor *endpoint;
struct wacom *wacom;
static struct fb_info fb_info;
- /*
- * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
- * (Imported from arch/m68k/amiga/amisound.c)
- */
-
-extern volatile u_short amiga_audio_min_period;
-
/*
* Since we can't read the palette on OCS/ECS, and since reading one
* single color palette entry requires 5 expensive custom chip bus accesses
if (!strcmp(this_opt, "inverse")) {
amifb_inverse = 1;
fb_invert_cmaps();
+ } else if (!strcmp(this_opt, "off")) {
+ amifb_video_off();
} else if (!strcmp(this_opt, "ilbm"))
amifb_ilbm = 1;
else if (!strncmp(this_opt, "monitorcap:", 11))
* access the videomem with writethrough cache
*/
videomemory_phys = (u_long)ZTWO_PADDR(videomemory);
- videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize);
+ //videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize);
if (!videomemory) {
printk("amifb: WARNING! unable to map videomem cached writethrough\n");
videomemory = ZTWO_VADDR(videomemory_phys);
ami_init_copper();
- if (request_irq(IRQ_AMIGA_AUTO_3, amifb_interrupt, 0,
- "fb vertb handler", NULL)) {
+ if (request_irq(IRQ_AMIGA_VERTB, amifb_interrupt, 0,
+ "fb vertb handler", ¤tpar)) {
err = -EBUSY;
goto amifb_error;
}
- amiga_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER;
- amiga_intena_vals[IRQ_AMIGA_COPPER] = 0;
- custom.intena = IF_VERTB;
- custom.intena = IF_SETCLR | IF_COPER;
amifb_set_var(&var, -1, &fb_info);
static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
{
- u_short ints = custom.intreqr & custom.intenar;
- static struct irq_server server = {0, 0};
- unsigned long flags;
-
- if (ints & IF_BLIT) {
- custom.intreq = IF_BLIT;
- amiga_do_irq(IRQ_AMIGA_BLIT, fp);
- }
-
- if (ints & IF_COPER) {
- custom.intreq = IF_COPER;
- if (do_vmode_pan || do_vmode_full)
- ami_update_display();
-
- if (do_vmode_full)
- ami_init_display();
-
- if (do_vmode_pan) {
- flash_cursor();
- ami_rebuild_copper();
- do_cursor = do_vmode_pan = 0;
- } else if (do_cursor) {
- flash_cursor();
+ if (do_vmode_pan || do_vmode_full)
+ ami_update_display();
+
+ if (do_vmode_full)
+ ami_init_display();
+
+ if (do_vmode_pan) {
+ flash_cursor();
+ ami_rebuild_copper();
+ do_cursor = do_vmode_pan = 0;
+ } else if (do_cursor) {
+ flash_cursor();
+ ami_set_sprite();
+ do_cursor = 0;
+ } else {
+ if (flash_cursor())
ami_set_sprite();
- do_cursor = 0;
- } else {
- if (flash_cursor())
- ami_set_sprite();
- }
-
- save_flags(flags);
- cli();
- if (get_vbpos() < down2(currentpar.diwstrt_v - 6))
- custom.copjmp2 = 0;
- restore_flags(flags);
-
- if (do_blank) {
- ami_do_blank();
- do_blank = 0;
- }
+ }
- if (do_vmode_full) {
- ami_reinit_copper();
- do_vmode_full = 0;
- }
- amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server);
+ if (do_blank) {
+ ami_do_blank();
+ do_blank = 0;
}
- if (ints & IF_VERTB) {
- printk("%s: Warning: IF_VERTB was enabled\n", __FUNCTION__);
- custom.intena = IF_VERTB;
+ if (do_vmode_full) {
+ ami_reinit_copper();
+ do_vmode_full = 0;
}
}
{
unregister_framebuffer(&fb_info);
amifb_deinit();
+ amifb_video_off();
}
#endif /* MODULE */
1, fbhw->setcolreg, info);
}
+static int
+atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+ struct atafb_par par;
+ if (con == -1)
+ atafb_get_par(&par);
+ else {
+ int err;
+ if ((err=fbhw->decode_var(&fb_display[con].var,&par)))
+ return err;
+ }
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ return fbhw->encode_fix(fix, &par);
+}
+
static int
atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
#endif /* ATAFB_EXT */
mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
- screen_base = atari_stram_alloc(mem_req, NULL, "atafb");
+ screen_base = atari_stram_alloc(mem_req, "atafb");
if (!screen_base)
panic("Cannot allocate screen memory");
memset(screen_base, 0, mem_req);
* lru_list_lock > hash_table_lock > free_list_lock > unused_list_lock
*/
+#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_inode_buffers)
+
/*
* Hash table gook..
*/
return 0;
}
+void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+{
+ spin_lock(&lru_list_lock);
+ if (bh->b_inode)
+ list_del(&bh->b_inode_buffers);
+ bh->b_inode = inode;
+ list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
+ spin_unlock(&lru_list_lock);
+}
+
+/* The caller must have the lru_list lock before calling the
+ remove_inode_queue functions. */
+static void __remove_inode_queue(struct buffer_head *bh)
+{
+ bh->b_inode = NULL;
+ list_del(&bh->b_inode_buffers);
+}
+
+static inline void remove_inode_queue(struct buffer_head *bh)
+{
+ if (bh->b_inode)
+ __remove_inode_queue(bh);
+}
+
+int inode_has_buffers(struct inode *inode)
+{
+ int ret;
+
+ spin_lock(&lru_list_lock);
+ ret = !list_empty(&inode->i_dirty_buffers);
+ spin_unlock(&lru_list_lock);
+
+ return ret;
+}
+
+
/* If invalidate_buffers() will trash dirty buffers, it means some kind
of fs corruption is going on. Trashing dirty data always imply losing
information that was supposed to be just stored on the physical layer
write_lock(&hash_table_lock);
if (!atomic_read(&bh->b_count) &&
(destroy_dirty_buffers || !buffer_dirty(bh))) {
+ remove_inode_queue(bh);
__remove_from_queues(bh);
put_last_free(bh);
}
printk(KERN_WARNING
"set_blocksize: dev %s buffer_dirty %lu size %hu\n",
kdevname(dev), bh->b_blocknr, bh->b_size);
+ remove_inode_queue(bh);
__remove_from_queues(bh);
put_last_free(bh);
} else {
return;
}
+/*
+ * Synchronise all the inode's dirty buffers to the disk.
+ *
+ * We have conflicting pressures: we want to make sure that all
+ * initially dirty buffers get waited on, but that any subsequently
+ * dirtied buffers don't. After all, we don't want fsync to last
+ * forever if somebody is actively writing to the file.
+ *
+ * Do this in two main stages: first we copy dirty buffers to a
+ * temporary inode list, queueing the writes as we go. Then we clean
+ * up, waiting for those writes to complete.
+ *
+ * During this second stage, any subsequent updates to the file may end
+ * up refiling the buffer on the original inode's dirty list again, so
+ * there is a chance we will end up with a buffer queued for write but
+ * not yet completed on that list. So, as a final cleanup we go through
+ * the osync code to catch these locked, dirty buffers without requeuing
+ * any newly dirty buffers for write.
+ */
+
+int fsync_inode_buffers(struct inode *inode)
+{
+ struct buffer_head *bh;
+ struct inode tmp;
+ int err = 0, err2;
+
+ INIT_LIST_HEAD(&tmp.i_dirty_buffers);
+
+ spin_lock(&lru_list_lock);
+
+ while (!list_empty(&inode->i_dirty_buffers)) {
+ bh = BH_ENTRY(inode->i_dirty_buffers.next);
+ list_del(&bh->b_inode_buffers);
+ if (!buffer_dirty(bh) && !buffer_locked(bh))
+ bh->b_inode = NULL;
+ else {
+ bh->b_inode = &tmp;
+ list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
+ atomic_inc(&bh->b_count);
+ if (buffer_dirty(bh)) {
+ spin_unlock(&lru_list_lock);
+ ll_rw_block(WRITE, 1, &bh);
+ spin_lock(&lru_list_lock);
+ }
+ }
+ }
+
+ while (!list_empty(&tmp.i_dirty_buffers)) {
+ bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
+ remove_inode_queue(bh);
+ spin_unlock(&lru_list_lock);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh))
+ err = -EIO;
+ brelse(bh);
+ spin_lock(&lru_list_lock);
+ }
+
+ spin_unlock(&lru_list_lock);
+ err2 = osync_inode_buffers(inode);
+
+ if (err)
+ return err;
+ else
+ return err2;
+}
+
+
+/*
+ * osync is designed to support O_SYNC io. It waits synchronously for
+ * all already-submitted IO to complete, but does not queue any new
+ * writes to the disk.
+ *
+ * To do O_SYNC writes, just queue the buffer writes with ll_rw_block as
+ * you dirty the buffers, and then use osync_inode_buffers to wait for
+ * completion. Any other dirty buffers which are not yet queued for
+ * write will not be flushed to disk by the osync.
+ */
+
+int osync_inode_buffers(struct inode *inode)
+{
+ struct buffer_head *bh;
+ struct list_head *list;
+ int err = 0;
+
+ spin_lock(&lru_list_lock);
+
+ repeat:
+
+ for (list = inode->i_dirty_buffers.prev;
+ bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
+ list = bh->b_inode_buffers.prev) {
+ if (buffer_locked(bh)) {
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
+ wait_on_buffer(bh);
+ brelse(bh);
+ if (!buffer_uptodate(bh))
+ err = -EIO;
+ spin_lock(&lru_list_lock);
+ goto repeat;
+ }
+ }
+
+ spin_unlock(&lru_list_lock);
+ return err;
+}
+
+
+/*
+ * Invalidate any and all dirty buffers on a given inode. We are
+ * probably unmounting the fs, but that doesn't mean we have already
+ * done a sync(). Just drop the buffers from the inode list.
+ */
+
+void invalidate_inode_buffers(struct inode *inode)
+{
+ struct list_head *list, *next;
+
+ spin_lock(&lru_list_lock);
+ list = inode->i_dirty_buffers.next;
+ while (list != &inode->i_dirty_buffers) {
+ next = list->next;
+ remove_inode_queue(BH_ENTRY(list));
+ list = next;
+ }
+ spin_unlock(&lru_list_lock);
+}
+
+
/*
* Ok, this is getblk, and it isn't very clear, again to hinder
* race-conditions. Most of the code is seldom used, (ie repeating),
if (dispose != bh->b_list) {
__remove_from_lru_list(bh, bh->b_list);
bh->b_list = dispose;
+ if (dispose == BUF_CLEAN)
+ remove_inode_queue(bh);
__insert_into_lru_list(bh, dispose);
}
}
if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf))
goto in_use;
__hash_unlink(buf);
+ remove_inode_queue(buf);
write_unlock(&hash_table_lock);
__remove_from_lru_list(buf, buf->b_list);
spin_unlock(&lru_list_lock);
*/
static __inline__ void __put_unused_buffer_head(struct buffer_head * bh)
{
+ if (bh->b_inode)
+ BUG();
if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
kmem_cache_free(bh_cachep, bh);
} else {
}
set_bit(BH_Uptodate, &bh->b_state);
if (!atomic_set_buffer_dirty(bh)) {
+ buffer_insert_inode_queue(bh, inode);
__mark_dirty(bh);
need_balance_dirty = 1;
}
set_bit(BH_Uptodate, &bh->b_state);
if (!atomic_set_buffer_dirty(bh)) {
__mark_dirty(bh);
+ buffer_insert_inode_queue(bh, inode);
need_balance_dirty = 1;
}
}
/* The buffer can be either on the regular
* queues or on the free list..
*/
- if (p->b_dev != B_FREE)
+ if (p->b_dev != B_FREE) {
+ remove_inode_queue(p);
__remove_from_queues(p);
- else
+ } else
__remove_from_free_list(p, index);
__put_unused_buffer_head(p);
} while (tmp != bh);
#include <linux/smp_lock.h>
-#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
-#define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
-
-static int sync_indirect(struct inode * inode, u32 * block, int wait)
-{
- struct buffer_head * bh;
-
- if (!*block)
- return 0;
- bh = get_hash_table(inode->i_dev, le32_to_cpu(*block), blocksize);
- if (!bh)
- return 0;
- if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
- /* There can be a parallell read(2) that started read-I/O
- on the buffer so we can't assume that there's been
- an I/O error without first waiting I/O completation. */
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
- {
- brelse (bh);
- return -1;
- }
- }
- if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
- if (wait)
- /* when we return from fsync all the blocks
- must be _just_ stored on disk */
- wait_on_buffer(bh);
- brelse(bh);
- return 0;
- }
- ll_rw_block(WRITE, 1, &bh);
- atomic_dec(&bh->b_count);
- return 0;
-}
-
-static int sync_iblock(struct inode * inode, u32 * iblock,
- struct buffer_head ** bh, int wait)
-{
- int rc, tmp;
-
- *bh = NULL;
- tmp = le32_to_cpu(*iblock);
- if (!tmp)
- return 0;
- rc = sync_indirect(inode, iblock, wait);
- if (rc)
- return rc;
- *bh = bread(inode->i_dev, tmp, blocksize);
- if (!*bh)
- return -1;
- return 0;
-}
-
-static int sync_dindirect(struct inode * inode, u32 * diblock, int wait)
-{
- int i;
- struct buffer_head * dind_bh;
- int rc, err = 0;
-
- rc = sync_iblock(inode, diblock, &dind_bh, wait);
- if (rc || !dind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_indirect(inode, ((u32 *) dind_bh->b_data) + i, wait);
- if (rc)
- err = rc;
- }
- brelse(dind_bh);
- return err;
-}
-
-static int sync_tindirect(struct inode * inode, u32 * tiblock, int wait)
-{
- int i;
- struct buffer_head * tind_bh;
- int rc, err = 0;
-
- rc = sync_iblock(inode, tiblock, &tind_bh, wait);
- if (rc || !tind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_dindirect(inode, ((u32 *) tind_bh->b_data) + i, wait);
- if (rc)
- err = rc;
- }
- brelse(tind_bh);
- return err;
-}
-
/*
* File may be NULL when we are called. Perhaps we shouldn't
* even pass file to fsync ?
int ext2_sync_file(struct file * file, struct dentry *dentry, int datasync)
{
- int wait, err = 0;
struct inode *inode = dentry->d_inode;
+ return ext2_fsync_inode(inode, datasync);
+}
- lock_kernel();
- if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
- /*
- * Don't sync fast links!
- */
- goto skip;
-
- err = generic_buffer_fdatasync(inode, 0, ~0UL);
-
- for (wait=0; wait<=1; wait++)
- {
- err |= sync_indirect(inode,
- inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
- wait);
- err |= sync_dindirect(inode,
- inode->u.ext2_i.i_data+EXT2_DIND_BLOCK,
- wait);
- err |= sync_tindirect(inode,
- inode->u.ext2_i.i_data+EXT2_TIND_BLOCK,
- wait);
- }
-skip:
- err |= ext2_sync_inode (inode);
- unlock_kernel();
+int ext2_fsync_inode(struct inode *inode, int datasync)
+{
+ int err;
+
+ err = fsync_inode_buffers(inode);
+ if (!(inode->i_state & I_DIRTY))
+ return err;
+ if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ return err;
+
+ err |= ext2_sync_inode(inode);
return err ? -EIO : 0;
}
branch[n].p = (u32*) bh->b_data + offsets[n];
*branch[n].p = branch[n].key;
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh);
+ mark_buffer_dirty_inode(bh, inode);
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
/* had we spliced it onto indirect block? */
if (where->bh) {
- mark_buffer_dirty(where->bh);
+ mark_buffer_dirty_inode(where->bh, inode);
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
ll_rw_block (WRITE, 1, &where->bh);
wait_on_buffer(where->bh);
wait_on_buffer(bh);
memset(bh->b_data, 0, inode->i_sb->s_blocksize);
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh);
+ mark_buffer_dirty_inode(bh, inode);
}
return bh;
}
if (partial == chain)
mark_inode_dirty(inode);
else
- mark_buffer_dirty(partial->bh);
+ mark_buffer_dirty_inode(partial->bh, inode);
ext2_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
}
/* Clear the ends of indirect blocks on the shared branch */
partial->p + 1,
(u32*)partial->bh->b_data + addr_per_block,
(chain+n-1) - partial);
- mark_buffer_dirty(partial->bh);
+ mark_buffer_dirty_inode(partial->bh, inode);
if (IS_SYNC(inode)) {
ll_rw_block (WRITE, 1, &partial->bh);
wait_on_buffer (partial->bh);
raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
else for (block = 0; block < EXT2_N_BLOCKS; block++)
raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
- mark_buffer_dirty(bh);
+ mark_buffer_dirty_inode(bh, inode);
if (do_sync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
dir->i_version = ++event;
- mark_buffer_dirty(bh);
+ mark_buffer_dirty_inode(bh, dir);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
else
de->inode = 0;
dir->i_version = ++event;
- mark_buffer_dirty(bh);
+ mark_buffer_dirty_inode(bh, dir);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
strcpy (de->name, "..");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
inode->i_nlink = 2;
- mark_buffer_dirty(dir_block);
+ mark_buffer_dirty_inode(dir_block, dir);
brelse (dir_block);
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
EXT2_FEATURE_INCOMPAT_FILETYPE))
new_de->file_type = old_de->file_type;
new_dir->i_version = ++event;
- mark_buffer_dirty(new_bh);
+ mark_buffer_dirty_inode(new_bh, new_dir);
if (IS_SYNC(new_dir)) {
ll_rw_block (WRITE, 1, &new_bh);
wait_on_buffer (new_bh);
mark_inode_dirty(old_dir);
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
- mark_buffer_dirty(dir_bh);
+ mark_buffer_dirty_inode(dir_bh, old_inode);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
INIT_LIST_HEAD(&inode->i_hash);
INIT_LIST_HEAD(&inode->i_data.pages);
INIT_LIST_HEAD(&inode->i_dentry);
+ INIT_LIST_HEAD(&inode->i_dirty_buffers);
sema_init(&inode->i_sem, 1);
sema_init(&inode->i_zombie, 1);
spin_lock_init(&inode->i_data.i_shared_lock);
* Mark an inode as dirty. Callers should use mark_inode_dirty.
*/
-void __mark_inode_dirty(struct inode *inode)
+void __mark_inode_dirty(struct inode *inode, int flags)
{
struct super_block * sb = inode->i_sb;
if (sb) {
spin_lock(&inode_lock);
- if (!(inode->i_state & I_DIRTY)) {
- inode->i_state |= I_DIRTY;
+ if ((inode->i_state & flags) != flags) {
+ inode->i_state |= flags;
/* Only add valid (ie hashed) inodes to the dirty list */
if (!list_empty(&inode->i_hash)) {
list_del(&inode->i_list);
? &inode_in_use
: &inode_unused);
/* Set I_LOCK, reset I_DIRTY */
- inode->i_state ^= I_DIRTY | I_LOCK;
+ inode->i_state |= I_LOCK;
+ inode->i_state &= ~I_DIRTY;
spin_unlock(&inode_lock);
write_inode(inode, sync);
printk("write_inode_now: no super block\n");
}
+/**
+ * generic_osync_inode - flush all dirty data for a given inode to disk
+ * @inode: inode to write
+ * @datasync: if set, don't bother flushing timestamps
+ *
+ * This can be called by file_write functions for files which have the
+ * O_SYNC flag set, to flush dirty writes to disk.
+ */
+
+int generic_osync_inode(struct inode *inode, int datasync)
+{
+ int err;
+
+ /*
+ * WARNING
+ *
+ * Currently, the filesystem write path does not pass the
+ * filp down to the low-level write functions. Therefore it
+ * is impossible for (say) __block_commit_write to know if
+ * the operation is O_SYNC or not.
+ *
+ * Ideally, O_SYNC writes would have the filesystem call
+ * ll_rw_block as it went to kick-start the writes, and we
+ * could call osync_inode_buffers() here to wait only for
+ * those IOs which have already been submitted to the device
+ * driver layer. As it stands, if we did this we'd not write
+ * anything to disk since our writes have not been queued by
+ * this point: they are still on the dirty LRU.
+ *
+ * So, currently we will call fsync_inode_buffers() instead,
+ * to flush _all_ dirty buffers for this inode to disk on
+ * every O_SYNC write, not just the synchronous I/Os. --sct
+ */
+
+#ifdef WRITERS_QUEUE_IO
+ err = osync_inode_buffers(inode);
+#else
+ err = fsync_inode_buffers(inode);
+#endif
+
+ spin_lock(&inode_lock);
+ if (!(inode->i_state & I_DIRTY))
+ goto out;
+ if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ goto out;
+ spin_unlock(&inode_lock);
+ write_inode_now(inode, 1);
+ return err;
+
+ out:
+ spin_unlock(&inode_lock);
+ return err;
+}
+
/**
* clear_inode - clear an inode
* @inode: inode to clear
* dispose_list.
*/
#define CAN_UNUSE(inode) \
- (((inode)->i_state | (inode)->i_data.nrpages) == 0)
+ ((((inode)->i_state | (inode)->i_data.nrpages) == 0) && \
+ !inode_has_buffers(inode))
#define INODE(entry) (list_entry(entry, struct inode, i_list))
void prune_icache(int goal)
if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
if ( IS_RDONLY (inode) ) return;
inode->i_atime = CURRENT_TIME;
- mark_inode_dirty (inode);
+ mark_inode_dirty_sync (inode);
} /* End Function update_atime */
* disable interrupts while they operate. (You have to provide inline
* routines to cli() and sti().)
*
- * Also note, these routines assume that you have 32 bit integers.
+ * Also note, these routines assume that you have 32 bit longs.
* You will have to change this if you are trying to port Linux to the
* Alpha architecture or to a Cray. :-)
*
* C language equivalents written by Theodore Ts'o, 9/26/92
*/
-extern __inline__ int set_bit(int nr,int * addr)
+extern __inline__ int set_bit(int nr,long * addr)
{
int mask, retval;
return retval;
}
-extern __inline__ int clear_bit(int nr, int * addr)
+extern __inline__ int clear_bit(int nr, long * addr)
{
int mask, retval;
return retval;
}
-extern __inline__ int test_bit(int nr, int * addr)
+extern __inline__ int test_bit(int nr, long * addr)
{
int mask;
#define MTRRIOC_DEL_ENTRY _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry)
#define MTRRIOC_GET_ENTRY _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry)
#define MTRRIOC_KILL_ENTRY _IOW(MTRR_IOCTL_BASE, 4, struct mtrr_sentry)
+#define MTRRIOC_ADD_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 5, struct mtrr_sentry)
+#define MTRRIOC_SET_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 6, struct mtrr_sentry)
+#define MTRRIOC_DEL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 7, struct mtrr_sentry)
+#define MTRRIOC_GET_PAGE_ENTRY _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry)
+#define MTRRIOC_KILL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 9, struct mtrr_sentry)
/* These are the region types */
#define MTRR_TYPE_UNCACHABLE 0
# ifdef CONFIG_MTRR
extern int mtrr_add (unsigned long base, unsigned long size,
unsigned int type, char increment);
+extern int mtrr_add_page (unsigned long base, unsigned long size,
+ unsigned int type, char increment);
extern int mtrr_del (int reg, unsigned long base, unsigned long size);
+extern int mtrr_del_page (int reg, unsigned long base, unsigned long size);
# else
static __inline__ int mtrr_add (unsigned long base, unsigned long size,
unsigned int type, char increment)
{
return -ENODEV;
}
+static __inline__ int mtrr_add_page (unsigned long base, unsigned long size,
+ unsigned int type, char increment)
+{
+ return -ENODEV;
+}
static __inline__ int mtrr_del (int reg, unsigned long base,
unsigned long size)
{
return -ENODEV;
}
+static __inline__ int mtrr_del_page (int reg, unsigned long base,
+ unsigned long size)
+{
+ return -ENODEV;
+}
# endif
/* The following functions are for initialisation: don't use them! */
#ifndef _M68K_AMIGAHW_H
#define _M68K_AMIGAHW_H
+#include <linux/ioport.h>
+
/*
* Different Amiga models
*/
#define ciab ((*(volatile struct CIA *)(zTwoBase + CIAB_PHYSADDR)))
#define CHIP_PHYSADDR (0x000000)
-#define chipaddr ((unsigned long)(zTwoBase + CHIP_PHYSADDR))
+
void amiga_chip_init (void);
-void *amiga_chip_alloc (long size, const char *name);
-void amiga_chip_free (void *);
+void *amiga_chip_alloc(unsigned long size, const char *name);
+void *amiga_chip_alloc_res(unsigned long size, struct resource *res);
+void amiga_chip_free(void *ptr);
unsigned long amiga_chip_avail( void ); /*MILAN*/
+extern volatile unsigned short amiga_audio_min_period;
+
+static inline void amifb_video_off(void)
+{
+ if (amiga_chipset == CS_ECS || amiga_chipset == CS_AGA) {
+ /* program Denise/Lisa for a higher maximum play rate */
+ custom.htotal = 113; /* 31 kHz */
+ custom.vtotal = 223; /* 70 Hz */
+ custom.beamcon0 = 0x4390; /* HARDDIS, VAR{BEAM,VSY,HSY,CSY}EN */
+ /* suspend the monitor */
+ custom.hsstrt = custom.hsstop = 116;
+ custom.vsstrt = custom.vsstop = 226;
+ amiga_audio_min_period = 57;
+ }
+}
struct tod3000 {
unsigned int :28, second2:4; /* lower digit */
#define IF_DSKBLK 0x0002 /* diskblock DMA finished */
#define IF_TBE 0x0001 /* serial transmit buffer empty interrupt */
-struct irq_server {
- unsigned short count, reentrance;
-};
-
extern void amiga_do_irq(int irq, struct pt_regs *fp);
-extern void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server);
+extern void amiga_do_irq_list(int irq, struct pt_regs *fp);
extern unsigned short amiga_intena_vals[];
static inline void pcmcia_ack_int(u_char intreq)
{
- gayle.intreq = ((intreq & 0x2c) ^ 0x2c) | 0xc0;
+ gayle.intreq = 0xf8;
}
static inline void pcmcia_enable_irq(void)
{
- gayle.inten = GAYLE_IRQ_IDE|GAYLE_IRQ_IRQ;
+ gayle.inten |= GAYLE_IRQ_IRQ;
}
static inline void pcmcia_disable_irq(void)
{
- gayle.inten = GAYLE_IRQ_IDE;
+ gayle.inten &= ~GAYLE_IRQ_IRQ;
}
#define PCMCIA_INSERTED (gayle.cardstatus & GAYLE_CS_CCDET)
*/
/* public interface */
-void *atari_stram_alloc( long size, unsigned long *start_mem,
- const char *owner );
-void atari_stram_free( void *);
+void *atari_stram_alloc(long size, const char *owner);
+void atari_stram_free(void *);
/* functions called internally by other parts of the kernel */
-void atari_stram_init( void);
-void atari_stram_reserve_pages( unsigned long start_mem );
+void atari_stram_init(void);
+void atari_stram_reserve_pages(void *start_mem);
+void atari_stram_mem_init_hook (void);
#endif /*_M68K_ATARI_STRAM_H */
*/
#include <linux/mm.h>
-#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
static inline void dma_cache_maintenance( unsigned long paddr,
unsigned long len,
return retval;
}
+/*
+ * clear_bit() doesn't provide any barrier for the compiler.
+ */
+#define smp_mb__before_clear_bit() barrier()
+#define smp_mb__after_clear_bit() barrier()
+
#define clear_bit(nr,vaddr) \
(__builtin_constant_p(nr) ? \
__constant_clear_bit(nr, vaddr) : \
LFLUSH_I_AND_D = 0x00000808
LSIGTRAP = 5
-/* process bits for task_struct.flags */
-PF_TRACESYS_OFF = 3
-PF_TRACESYS_BIT = 5
-PF_PTRACED_OFF = 3
-PF_PTRACED_BIT = 4
-PF_DTRACE_OFF = 1
-PF_DTRACE_BIT = 5
+/* process bits for task_struct.ptrace */
+PT_TRACESYS_OFF = 3
+PT_TRACESYS_BIT = 1
+PT_PTRACED_OFF = 3
+PT_PTRACED_BIT = 0
+PT_DTRACE_OFF = 3
+PT_DTRACE_BIT = 2
#define SAVE_ALL_INT save_all_int
#define SAVE_ALL_SYS save_all_sys
#define F_SETSIG 10 /* for sockets. */
#define F_GETSIG 11 /* for sockets. */
+#define F_GETLK64 12 /* using 'struct flock64' */
+#define F_SETLK64 13
+#define F_SETLKW64 14
+
/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
pid_t l_pid;
};
+struct flock64 {
+ short l_type;
+ short l_whence;
+ loff_t l_start;
+ loff_t l_len;
+ pid_t l_pid;
+};
+
#define F_LINUX_SPECIFIC_BASE 1024
#endif /* _M68K_FCNTL_H */
* This file contains the m68k architecture specific keyboard definitions
*/
-#include <linux/config.h> /* CONFIG_MAGIC_SYSRQ */
#ifndef __M68K_KEYBOARD_H
#define __M68K_KEYBOARD_H
return scancode > 127 ? -EINVAL : scancode;
}
-static __inline__ int kbd_translate(unsigned char scancode,
- unsigned char *keycode, char raw_mode)
-{
-#ifdef CONFIG_Q40
- if (MACH_IS_Q40)
- return q40kbd_translate(scancode,keycode,raw_mode);
-#endif
- *keycode = scancode;
- return 1;
-}
-
static __inline__ char kbd_unexpected_up(unsigned char keycode)
{
#ifdef CONFIG_Q40
mach_kbd_leds(leds);
}
-#ifdef CONFIG_MAGIC_SYSRQ
-#define kbd_is_sysrq(keycode) ((keycode) == mach_sysrq_key && \
- (up_flag || \
- (shift_state & mach_sysrq_shift_mask) == \
- mach_sysrq_shift_state))
-#define kbd_sysrq_xlate mach_sysrq_xlate
-#endif
+#define kbd_init_hw mach_keyb_init
+#define kbd_translate mach_kbd_translate
+
+#define kbd_sysrq_xlate mach_sysrq_xlate
+
+/* resource allocation */
+#define kbd_request_region()
+#define kbd_request_irq(handler)
-#define kbd_init_hw mach_keyb_init
+extern unsigned int SYSRQ_KEY;
#endif /* __KERNEL__ */
extern int (*mach_keyb_init) (void);
extern int (*mach_kbdrate) (struct kbd_repeat *);
extern void (*mach_kbd_leds) (unsigned int);
+extern int (*mach_kbd_translate)(unsigned char scancode, unsigned char *keycode, char raw_mode);
/* machine dependent irq functions */
extern void (*mach_init_IRQ) (void);
extern void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
--- /dev/null
+#ifndef _MOTOROLA_PGALLOC_H
+#define _MOTOROLA_PGALLOC_H
+
+extern struct pgtable_cache_struct {
+ unsigned long *pmd_cache;
+ unsigned long *pte_cache;
+/* This counts in units of pointer tables, of which can be eight per page. */
+ unsigned long pgtable_cache_sz;
+} quicklists;
+
+#define pgd_quicklist ((unsigned long *)0)
+#define pmd_quicklist (quicklists.pmd_cache)
+#define pte_quicklist (quicklists.pte_cache)
+/* This isn't accurate because of fragmentation of allocated pages for
+ pointer tables, but that should not be a problem. */
+#define pgtable_cache_size ((quicklists.pgtable_cache_sz+7)/8)
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset);
+extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset);
+
+extern pmd_t *get_pointer_table(void);
+extern int free_pointer_table(pmd_t *);
+
+extern inline pte_t *get_pte_fast(void)
+{
+ unsigned long *ret;
+
+ ret = pte_quicklist;
+ if (ret) {
+ pte_quicklist = (unsigned long *)*ret;
+ ret[0] = 0;
+ quicklists.pgtable_cache_sz -= 8;
+ }
+ return (pte_t *)ret;
+}
+
+extern inline void free_pte_fast(pte_t *pte)
+{
+ *(unsigned long *)pte = (unsigned long)pte_quicklist;
+ pte_quicklist = (unsigned long *)pte;
+ quicklists.pgtable_cache_sz += 8;
+}
+
+extern inline void free_pte_slow(pte_t *pte)
+{
+ cache_page((unsigned long)pte);
+ free_page((unsigned long) pte);
+}
+
+extern inline pmd_t *get_pmd_fast(void)
+{
+ unsigned long *ret;
+
+ ret = pmd_quicklist;
+ if (ret) {
+ pmd_quicklist = (unsigned long *)*ret;
+ ret[0] = 0;
+ quicklists.pgtable_cache_sz--;
+ }
+ return (pmd_t *)ret;
+}
+
+extern inline void free_pmd_fast(pmd_t *pmd)
+{
+ *(unsigned long *)pmd = (unsigned long)pmd_quicklist;
+ pmd_quicklist = (unsigned long *) pmd;
+ quicklists.pgtable_cache_sz++;
+}
+
+extern inline int free_pmd_slow(pmd_t *pmd)
+{
+ return free_pointer_table(pmd);
+}
+
+/* The pgd cache is folded into the pmd cache, so these are dummy routines. */
+extern inline pgd_t *get_pgd_fast(void)
+{
+ return (pgd_t *)0;
+}
+
+extern inline void free_pgd_fast(pgd_t *pgd)
+{
+}
+
+extern inline void free_pgd_slow(pgd_t *pgd)
+{
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pmd(pgd_t *pgd);
+
+extern inline void pte_free(pte_t *pte)
+{
+ free_pte_fast(pte);
+}
+
+extern inline pte_t *pte_alloc(pmd_t *pmd, unsigned long address)
+{
+ address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+ if (pmd_none(*pmd)) {
+ pte_t *page = get_pte_fast();
+
+ if (!page)
+ return get_pte_slow(pmd, address);
+ pmd_set(pmd,page);
+ return page + address;
+ }
+ if (pmd_bad(*pmd)) {
+ __bad_pte(pmd);
+ return NULL;
+ }
+ return (pte_t *)__pmd_page(*pmd) + address;
+}
+
+extern inline void pmd_free(pmd_t *pmd)
+{
+ free_pmd_fast(pmd);
+}
+
+extern inline pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
+{
+ address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+ if (pgd_none(*pgd)) {
+ pmd_t *page = get_pmd_fast();
+
+ if (!page)
+ return get_pmd_slow(pgd, address);
+ pgd_set(pgd, page);
+ return page + address;
+ }
+ if (pgd_bad(*pgd)) {
+ __bad_pmd(pgd);
+ return NULL;
+ }
+ return (pmd_t *)__pgd_page(*pgd) + address;
+}
+
+extern inline void pte_free_kernel(pte_t *pte)
+{
+ free_pte_fast(pte);
+}
+
+extern inline pte_t *pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+{
+ return pte_alloc(pmd, address);
+}
+
+extern inline void pmd_free_kernel(pmd_t *pmd)
+{
+ free_pmd_fast(pmd);
+}
+
+extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+{
+ return pmd_alloc(pgd, address);
+}
+
+extern inline void pgd_free(pgd_t *pgd)
+{
+ free_pmd_fast((pmd_t *)pgd);
+}
+
+extern inline pgd_t *pgd_alloc(void)
+{
+ pgd_t *pgd = (pgd_t *)get_pmd_fast();
+ if (!pgd)
+ pgd = (pgd_t *)get_pointer_table();
+ return pgd;
+}
+
+extern int do_check_pgt_cache(int, int);
+
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+}
+
+
+/*
+ * flush all user-space atc entries.
+ */
+static inline void __flush_tlb(void)
+{
+ if (CPU_IS_040_OR_060)
+ __asm__ __volatile__(".chip 68040\n\t"
+ "pflushan\n\t"
+ ".chip 68k");
+ else
+ __asm__ __volatile__("pflush #0,#4");
+}
+
+static inline void __flush_tlb040_one(unsigned long addr)
+{
+ __asm__ __volatile__(".chip 68040\n\t"
+ "pflush (%0)\n\t"
+ ".chip 68k"
+ : : "a" (addr));
+}
+
+static inline void __flush_tlb_one(unsigned long addr)
+{
+ if (CPU_IS_040_OR_060)
+ __flush_tlb040_one(addr);
+ else
+ __asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr));
+}
+
+#define flush_tlb() __flush_tlb()
+
+/*
+ * flush all atc entries (both kernel and user-space entries).
+ */
+static inline void flush_tlb_all(void)
+{
+ if (CPU_IS_040_OR_060)
+ __asm__ __volatile__(".chip 68040\n\t"
+ "pflusha\n\t"
+ ".chip 68k");
+ else
+ __asm__ __volatile__("pflusha");
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+ if (mm == current->mm)
+ __flush_tlb();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+{
+ if (vma->vm_mm == current->mm)
+ __flush_tlb_one(addr);
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ if (mm == current->mm)
+ __flush_tlb();
+}
+
+extern inline void flush_tlb_kernel_page(unsigned long addr)
+{
+ if (CPU_IS_040_OR_060) {
+ mm_segment_t old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ __asm__ __volatile__(".chip 68040\n\t"
+ "pflush (%0)\n\t"
+ ".chip 68k"
+ : : "a" (addr));
+ set_fs(old_fs);
+ } else
+ __asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
+}
+
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+}
+
+#endif /* _MOTOROLA_PGALLOC_H */
--- /dev/null
+#ifndef _MOTOROLA_PGTABLE_H
+#define _MOTOROLA_PGTABLE_H
+
+/*
+ * Definitions for MMU descriptors
+ */
+#define _PAGE_PRESENT 0x001
+#define _PAGE_SHORT 0x002
+#define _PAGE_RONLY 0x004
+#define _PAGE_ACCESSED 0x008
+#define _PAGE_DIRTY 0x010
+#define _PAGE_SUPER 0x080 /* 68040 supervisor only */
+#define _PAGE_FAKE_SUPER 0x200 /* fake supervisor only on 680[23]0 */
+#define _PAGE_GLOBAL040 0x400 /* 68040 global bit, used for kva descs */
+#define _PAGE_COW 0x800 /* implemented in software */
+#define _PAGE_NOCACHE030 0x040 /* 68030 no-cache mode */
+#define _PAGE_NOCACHE 0x060 /* 68040 cache mode, non-serialized */
+#define _PAGE_NOCACHE_S 0x040 /* 68040 no-cache mode, serialized */
+#define _PAGE_CACHE040 0x020 /* 68040 cache mode, cachable, copyback */
+#define _PAGE_CACHE040W 0x000 /* 68040 cache mode, cachable, write-through */
+
+#define _DESCTYPE_MASK 0x003
+
+#define _CACHEMASK040 (~0x060)
+#define _TABLE_MASK (0xfffffe00)
+
+#define _PAGE_TABLE (_PAGE_SHORT)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_NOCACHE)
+
+#ifndef __ASSEMBLY__
+
+/* This is the cache mode to be used for pages containing page descriptors for
+ * processors >= '040. It is in pte_mknocache(), and the variable is defined
+ * and initialized in head.S */
+extern int m68k_pgtable_cachemode;
+
+/* This is the cache mode for normal pages, for supervisor access on
+ * processors >= '040. It is used in pte_mkcache(), and the variable is
+ * defined and initialized in head.S */
+
+#if defined(CONFIG_060_WRITETHROUGH)
+extern int m68k_supervisor_cachemode;
+#else
+#define m68k_supervisor_cachemode _PAGE_CACHE040
+#endif
+
+#if defined(CPU_M68040_OR_M68060_ONLY)
+#define mm_cachebits _PAGE_CACHE040
+#elif defined(CPU_M68020_OR_M68030_ONLY)
+#define mm_cachebits 0
+#else
+extern unsigned long mm_cachebits;
+#endif
+
+#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | mm_cachebits)
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | mm_cachebits)
+#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | mm_cachebits)
+#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | mm_cachebits)
+#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | mm_cachebits)
+
+/* Alternate definitions that are compile time constants, for
+ initializing protection_map. The cachebits are fixed later. */
+#define PAGE_NONE_C __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED)
+#define PAGE_SHARED_C __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_COPY_C __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED)
+#define PAGE_READONLY_C __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED)
+
+/*
+ * The m68k can't do page protection for execute, and considers that the same are read.
+ * Also, write permissions imply read permissions. This is the closest we can get..
+ */
+#define __P000 PAGE_NONE_C
+#define __P001 PAGE_READONLY_C
+#define __P010 PAGE_COPY_C
+#define __P011 PAGE_COPY_C
+#define __P100 PAGE_READONLY_C
+#define __P101 PAGE_READONLY_C
+#define __P110 PAGE_COPY_C
+#define __P111 PAGE_COPY_C
+
+#define __S000 PAGE_NONE_C
+#define __S001 PAGE_READONLY_C
+#define __S010 PAGE_SHARED_C
+#define __S011 PAGE_SHARED_C
+#define __S100 PAGE_READONLY_C
+#define __S101 PAGE_READONLY_C
+#define __S110 PAGE_SHARED_C
+#define __S111 PAGE_SHARED_C
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define __mk_pte(page, pgprot) \
+({ \
+ pte_t __pte; \
+ \
+ pte_val(__pte) = __pa(page) + pgprot_val(pgprot); \
+ __pte; \
+})
+#define mk_pte(page, pgprot) __mk_pte(page_address(page), (pgprot))
+#define mk_pte_phys(physpage, pgprot) \
+({ \
+ pte_t __pte; \
+ \
+ pte_val(__pte) = (physpage) + pgprot_val(pgprot); \
+ __pte; \
+})
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+ unsigned long ptbl = virt_to_phys(ptep) | _PAGE_TABLE | _PAGE_ACCESSED;
+ unsigned long *ptr = pmdp->pmd;
+ short i = 16;
+ while (--i >= 0) {
+ *ptr++ = ptbl;
+ ptbl += (sizeof(pte_t)*PTRS_PER_PTE/16);
+ }
+}
+
+extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{ pgd_val(*pgdp) = _PAGE_TABLE | _PAGE_ACCESSED | __pa(pmdp); }
+
+#define __pte_page(pte) ((unsigned long)__va(pte_val(pte) & PAGE_MASK))
+#define __pmd_page(pmd) ((unsigned long)__va(pmd_val(pmd) & _TABLE_MASK))
+#define __pgd_page(pgd) ((unsigned long)__va(pgd_val(pgd) & _TABLE_MASK))
+
+
+#define pte_none(pte) (!pte_val(pte))
+#define pte_present(pte) (pte_val(pte) & (_PAGE_PRESENT | _PAGE_FAKE_SUPER))
+#define pte_clear(ptep) ({ pte_val(*(ptep)) = 0; })
+#define pte_pagenr(pte) ((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT)
+
+#define pmd_none(pmd) (!pmd_val(pmd))
+#define pmd_bad(pmd) ((pmd_val(pmd) & _DESCTYPE_MASK) != _PAGE_TABLE)
+#define pmd_present(pmd) (pmd_val(pmd) & _PAGE_TABLE)
+#define pmd_clear(pmdp) ({ \
+ unsigned long *__ptr = pmdp->pmd; \
+ short __i = 16; \
+ while (--__i >= 0) \
+ *__ptr++ = 0; \
+})
+
+
+#define pgd_none(pgd) (!pgd_val(pgd))
+#define pgd_bad(pgd) ((pgd_val(pgd) & _DESCTYPE_MASK) != _PAGE_TABLE)
+#define pgd_present(pgd) (pgd_val(pgd) & _PAGE_TABLE)
+#define pgd_clear(pgdp) ({ pgd_val(*pgdp) = 0; })
+/* Permanent address of a page. */
+#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; })
+#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
+#define pte_page(pte) (mem_map+pte_pagenr(pte))
+
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+extern inline int pte_read(pte_t pte) { return 1; }
+extern inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_RONLY); }
+extern inline int pte_exec(pte_t pte) { return 1; }
+extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
+extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
+
+extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_RONLY; return pte; }
+extern inline pte_t pte_rdprotect(pte_t pte) { return pte; }
+extern inline pte_t pte_exprotect(pte_t pte) { return pte; }
+extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) &= ~_PAGE_RONLY; return pte; }
+extern inline pte_t pte_mkread(pte_t pte) { return pte; }
+extern inline pte_t pte_mkexec(pte_t pte) { return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_mknocache(pte_t pte)
+{
+ pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_pgtable_cachemode;
+ return pte;
+}
+extern inline pte_t pte_mkcache(pte_t pte) { pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode; return pte; }
+
+#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
+
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+
+/* to find an entry in a page-table-directory */
+extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
+{
+ return mm->pgd + pgd_index(address);
+}
+
+#define swapper_pg_dir kernel_pg_dir
+extern pgd_t kernel_pg_dir[128];
+
+extern inline pgd_t * pgd_offset_k(unsigned long address)
+{
+ return kernel_pg_dir + (address >> PGDIR_SHIFT);
+}
+
+
+/* Find an entry in the second-level page table.. */
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+ return (pmd_t *)__pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PMD-1));
+}
+
+/* Find an entry in the third-level page table.. */
+extern inline pte_t * pte_offset(pmd_t * pmdp, unsigned long address)
+{
+ return (pte_t *)__pmd_page(*pmdp) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+}
+
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any.
+ */
+
+/* Prior to calling these routines, the page should have been flushed
+ * from both the cache and ATC, or the CPU might not notice that the
+ * cache setting for the page has been changed. -jskov
+ */
+static inline void nocache_page (unsigned long vaddr)
+{
+ if (CPU_IS_040_OR_060) {
+ pgd_t *dir;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ dir = pgd_offset_k(vaddr);
+ pmdp = pmd_offset(dir,vaddr);
+ ptep = pte_offset(pmdp,vaddr);
+ *ptep = pte_mknocache(*ptep);
+ }
+}
+
+static inline void cache_page (unsigned long vaddr)
+{
+ if (CPU_IS_040_OR_060) {
+ pgd_t *dir;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ dir = pgd_offset_k(vaddr);
+ pmdp = pmd_offset(dir,vaddr);
+ ptep = pte_offset(pmdp,vaddr);
+ *ptep = pte_mkcache(*ptep);
+ }
+}
+
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _MOTOROLA_PGTABLE_H */
#endif /* CONFIG_SUN3 */
#define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
-#define virt_to_page(kaddr) (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
+#define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr)-PAGE_OFFSET) >> PAGE_SHIFT))
#define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
#ifndef CONFIG_SUN3
#define MAXHOSTNAMELEN 64 /* max length of hostname */
+#ifdef __KERNEL__
+# define CLOCKS_PER_SEC HZ /* frequency at which times() counts */
+#endif
+
#endif /* _M68K_PARAM_H */
-#ifndef _M68K_PGALLOC_H
-#define _M68K_PGALLOC_H
+
+#ifndef M68K_PGALLOC_H
+#define M68K_PGALLOC_H
#include <asm/setup.h>
#include <asm/virtconvert.h>
-extern struct pgtable_cache_struct {
- unsigned long *pmd_cache;
- unsigned long *pte_cache;
-/* This counts in units of pointer tables, of which can be eight per page. */
- unsigned long pgtable_cache_sz;
-} quicklists;
-
-#define pgd_quicklist ((unsigned long *)0)
-#define pmd_quicklist (quicklists.pmd_cache)
-#define pte_quicklist (quicklists.pte_cache)
-/* This isn't accurate because of fragmentation of allocated pages for
- pointer tables, but that should not be a problem. */
-#define pgtable_cache_size ((quicklists.pgtable_cache_sz+7)/8)
-
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset);
-extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset);
-
-extern pmd_t *get_pointer_table(void);
-extern int free_pointer_table(pmd_t *);
-
-extern inline pte_t *get_pte_fast(void)
-{
- unsigned long *ret;
-
- ret = pte_quicklist;
- if (ret) {
- pte_quicklist = (unsigned long *)*ret;
- ret[0] = 0;
- quicklists.pgtable_cache_sz -= 8;
- }
- return (pte_t *)ret;
-}
-
-extern inline void free_pte_fast(pte_t *pte)
-{
- *(unsigned long *)pte = (unsigned long)pte_quicklist;
- pte_quicklist = (unsigned long *)pte;
- quicklists.pgtable_cache_sz += 8;
-}
-
-extern inline void free_pte_slow(pte_t *pte)
-{
- cache_page((unsigned long)pte);
- free_page((unsigned long) pte);
-}
-
-extern inline pmd_t *get_pmd_fast(void)
-{
- unsigned long *ret;
-
- ret = pmd_quicklist;
- if (ret) {
- pmd_quicklist = (unsigned long *)*ret;
- ret[0] = 0;
- quicklists.pgtable_cache_sz--;
- }
- return (pmd_t *)ret;
-}
-
-extern inline void free_pmd_fast(pmd_t *pmd)
-{
- *(unsigned long *)pmd = (unsigned long)pmd_quicklist;
- pmd_quicklist = (unsigned long *) pmd;
- quicklists.pgtable_cache_sz++;
-}
-
-extern inline int free_pmd_slow(pmd_t *pmd)
-{
- return free_pointer_table(pmd);
-}
-
-/* The pgd cache is folded into the pmd cache, so these are dummy routines. */
-extern inline pgd_t *get_pgd_fast(void)
-{
- return (pgd_t *)0;
-}
-
-extern inline void free_pgd_fast(pgd_t *pgd)
-{
-}
-
-extern inline void free_pgd_slow(pgd_t *pgd)
-{
-}
-
-extern void __bad_pte(pmd_t *pmd);
-extern void __bad_pmd(pgd_t *pgd);
-
-extern inline void pte_free(pte_t *pte)
-{
- free_pte_fast(pte);
-}
-
-extern inline pte_t *pte_alloc(pmd_t *pmd, unsigned long address)
-{
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t *page = get_pte_fast();
-
- if (!page)
- return get_pte_slow(pmd, address);
- pmd_set(pmd,page);
- return page + address;
- }
- if (pmd_bad(*pmd)) {
- __bad_pte(pmd);
- return NULL;
- }
- return (pte_t *)__pmd_page(*pmd) + address;
-}
-
-extern inline void pmd_free(pmd_t *pmd)
-{
- free_pmd_fast(pmd);
-}
-
-extern inline pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
-{
- address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
- if (pgd_none(*pgd)) {
- pmd_t *page = get_pmd_fast();
-
- if (!page)
- return get_pmd_slow(pgd, address);
- pgd_set(pgd, page);
- return page + address;
- }
- if (pgd_bad(*pgd)) {
- __bad_pmd(pgd);
- return NULL;
- }
- return (pmd_t *)__pgd_page(*pgd) + address;
-}
-
-extern inline void pte_free_kernel(pte_t *pte)
-{
- free_pte_fast(pte);
-}
-
-extern inline pte_t *pte_alloc_kernel(pmd_t *pmd, unsigned long address)
-{
- return pte_alloc(pmd, address);
-}
-
-extern inline void pmd_free_kernel(pmd_t *pmd)
-{
- free_pmd_fast(pmd);
-}
-
-extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
-{
- return pmd_alloc(pgd, address);
-}
-
-extern inline void pgd_free(pgd_t *pgd)
-{
- free_pmd_fast((pmd_t *)pgd);
-}
-
-extern inline pgd_t *pgd_alloc(void)
-{
- pgd_t *pgd = (pgd_t *)get_pmd_fast();
- if (!pgd)
- pgd = (pgd_t *)get_pointer_table();
- return pgd;
-}
-
-extern int do_check_pgt_cache(int, int);
-
-extern inline void set_pgdir(unsigned long address, pgd_t entry)
-{
-}
-
-
/*
* Cache handling functions
*/
}
}
+#define flush_icache_page(vma,pg) do { } while (0)
-/*
- * flush all user-space atc entries.
- */
-static inline void __flush_tlb(void)
-{
- if (CPU_IS_040_OR_060)
- __asm__ __volatile__(".chip 68040\n\t"
- "pflushan\n\t"
- ".chip 68k");
- else
- __asm__ __volatile__("pflush #0,#4");
-}
-
-static inline void __flush_tlb_one(unsigned long addr)
-{
- if (CPU_IS_040_OR_060) {
- __asm__ __volatile__(".chip 68040\n\t"
- "pflush (%0)\n\t"
- ".chip 68k"
- : : "a" (addr));
- } else
- __asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr));
-}
-
-#define flush_tlb() __flush_tlb()
-
-/*
- * flush all atc entries (both kernel and user-space entries).
- */
-static inline void flush_tlb_all(void)
-{
- if (CPU_IS_040_OR_060)
- __asm__ __volatile__(".chip 68040\n\t"
- "pflusha\n\t"
- ".chip 68k");
- else
- __asm__ __volatile__("pflusha");
-}
-
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
- if (mm == current->mm)
- __flush_tlb();
-}
-
-static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
-{
- if (vma->vm_mm == current->mm)
- __flush_tlb_one(addr);
-}
-
-static inline void flush_tlb_range(struct mm_struct *mm,
- unsigned long start, unsigned long end)
-{
- if (mm == current->mm)
- __flush_tlb();
-}
-extern inline void flush_tlb_kernel_page(unsigned long addr)
-{
- if (CPU_IS_040_OR_060) {
- mm_segment_t old_fs = get_fs();
- set_fs(KERNEL_DS);
- __asm__ __volatile__(".chip 68040\n\t"
- "pflush (%0)\n\t"
- ".chip 68k"
- : : "a" (addr));
- set_fs(old_fs);
- } else
- __asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
-}
-
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
- unsigned long start, unsigned long end)
-{
-}
+#ifdef CONFIG_SUN3
+#include <asm/sun3_pgalloc.h>
+#else
+#include <asm/motorola_pgalloc.h>
+#endif
-#endif /* _M68K_PGALLOC_H */
+#endif /* M68K_PGALLOC_H */
/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#ifdef CONFIG_SUN3
+#define PMD_SHIFT 17
+#else
#define PMD_SHIFT 22
+#endif
#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#ifdef CONFIG_SUN3
+#define PGDIR_SHIFT 17
+#else
#define PGDIR_SHIFT 25
+#endif
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
* entries per page directory level: the m68k is configured as three-level,
* so we do have PMD level physically.
*/
+#ifdef CONFIG_SUN3
+#define PTRS_PER_PTE 16
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PGD 2048
+#else
#define PTRS_PER_PTE 1024
#define PTRS_PER_PMD 8
#define PTRS_PER_PGD 128
+#endif
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
#define FIRST_USER_PGD_NR 0
/* Virtual address region for use by kernel_map() */
+#ifdef CONFIG_SUN3
+#define KMAP_START 0x0DC00000
+#define KMAP_END 0x0E000000
+#else
#define KMAP_START 0xd0000000
#define KMAP_END 0xf0000000
+#endif
+#ifndef CONFIG_SUN3
/* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
* physical memory until the kernel virtual memory starts. That means that
#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END KMAP_START
-
-#endif /* __ASSEMBLY__ */
-
-/*
- * Definitions for MMU descriptors
- */
-#define _PAGE_PRESENT 0x001
-#define _PAGE_SHORT 0x002
-#define _PAGE_RONLY 0x004
-#define _PAGE_ACCESSED 0x008
-#define _PAGE_DIRTY 0x010
-#define _PAGE_SUPER 0x080 /* 68040 supervisor only */
-#define _PAGE_FAKE_SUPER 0x200 /* fake supervisor only on 680[23]0 */
-#define _PAGE_GLOBAL040 0x400 /* 68040 global bit, used for kva descs */
-#define _PAGE_COW 0x800 /* implemented in software */
-#define _PAGE_NOCACHE030 0x040 /* 68030 no-cache mode */
-#define _PAGE_NOCACHE 0x060 /* 68040 cache mode, non-serialized */
-#define _PAGE_NOCACHE_S 0x040 /* 68040 no-cache mode, serialized */
-#define _PAGE_CACHE040 0x020 /* 68040 cache mode, cachable, copyback */
-#define _PAGE_CACHE040W 0x000 /* 68040 cache mode, cachable, write-through */
-
-/* Page protection values within PTE. */
-#define SUN3_PAGE_VALID (0x80000000)
-#define SUN3_PAGE_WRITEABLE (0x40000000)
-#define SUN3_PAGE_SYSTEM (0x20000000)
-#define SUN3_PAGE_NOCACHE (0x10000000)
-#define SUN3_PAGE_ACCESSED (0x02000000)
-#define SUN3_PAGE_MODIFIED (0x01000000)
-
-#define _DESCTYPE_MASK 0x003
-
-#define _CACHEMASK040 (~0x060)
-#define _TABLE_MASK (0xfffffe00)
-
-#define _PAGE_TABLE (_PAGE_SHORT)
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_NOCACHE)
-
-#ifndef __ASSEMBLY__
-
-/* This is the cache mode to be used for pages containing page descriptors for
- * processors >= '040. It is in pte_mknocache(), and the variable is defined
- * and initialized in head.S */
-extern int m68k_pgtable_cachemode;
-
-/* This is the cache mode for normal pages, for supervisor access on
- * processors >= '040. It is used in pte_mkcache(), and the variable is
- * defined and initialized in head.S */
-
-#if defined(CONFIG_060_WRITETHROUGH)
-extern int m68k_supervisor_cachemode;
-#else
-#define m68k_supervisor_cachemode _PAGE_CACHE040
-#endif
-
-#if defined(CPU_M68040_OR_M68060_ONLY)
-#define mm_cachebits _PAGE_CACHE040
-#elif defined(CPU_M68020_OR_M68030_ONLY)
-#define mm_cachebits 0
#else
-extern unsigned long mm_cachebits;
-#endif
-
-#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | mm_cachebits)
-#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | mm_cachebits)
-#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | mm_cachebits)
-#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | mm_cachebits)
-#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | mm_cachebits)
-
-/* Alternate definitions that are compile time constants, for
- initializing protection_map. The cachebits are fixed later. */
-#define PAGE_NONE_C __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED)
-#define PAGE_SHARED_C __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define PAGE_COPY_C __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED)
-#define PAGE_READONLY_C __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED)
-
-/*
- * The m68k can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
- */
-#define __P000 PAGE_NONE_C
-#define __P001 PAGE_READONLY_C
-#define __P010 PAGE_COPY_C
-#define __P011 PAGE_COPY_C
-#define __P100 PAGE_READONLY_C
-#define __P101 PAGE_READONLY_C
-#define __P110 PAGE_COPY_C
-#define __P111 PAGE_COPY_C
-
-#define __S000 PAGE_NONE_C
-#define __S001 PAGE_READONLY_C
-#define __S010 PAGE_SHARED_C
-#define __S011 PAGE_SHARED_C
-#define __S100 PAGE_READONLY_C
-#define __S101 PAGE_READONLY_C
-#define __S110 PAGE_SHARED_C
-#define __S111 PAGE_SHARED_C
+extern unsigned long vmalloc_end;
+#define VMALLOC_START 0x0f800000
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END vmalloc_end
+#endif /* CONFIG_SUN3 */
/* zero page used for uninitialized stuff */
extern unsigned long empty_zero_page;
/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
/* 64-bit machines, beware! SRB. */
-#define SIZEOF_PTR_LOG2 2
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-#define __mk_pte(page, pgprot) \
-({ \
- pte_t __pte; \
- \
- pte_val(__pte) = __pa((page) + pgprot_val(pgprot); \
- __pte; \
-})
-#define mk_pte(page, pgprot) __mk_pte(page_address(page), (pgprot))
-#define mk_pte_phys(physpage, pgprot) \
-({ \
- pte_t __pte; \
- \
- pte_val(__pte) = (physpage) + pgprot_val(pgprot); \
- __pte; \
-})
-
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
-
-extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
-{
- unsigned long ptbl = virt_to_phys(ptep) | _PAGE_TABLE | _PAGE_ACCESSED;
- unsigned long *ptr = pmdp->pmd;
- short i = 16;
- while (--i >= 0) {
- *ptr++ = ptbl;
- ptbl += (sizeof(pte_t)*PTRS_PER_PTE/16);
- }
-}
-
-extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{ pgd_val(*pgdp) = _PAGE_TABLE | _PAGE_ACCESSED | __pa(pmdp); }
-
-#define __pte_page(pte) ((unsigned long)__va(pte_val(pte) & PAGE_MASK))
-#define __pmd_page(pmd) ((unsigned long)__va(pmd_val(pmd) & _TABLE_MASK))
-#define __pgd_page(pgd) ((unsigned long)__va(pgd_val(pgd) & _TABLE_MASK))
-
-#define pte_none(pte) (!pte_val(pte))
-#define pte_present(pte) (pte_val(pte) & (_PAGE_PRESENT | _PAGE_FAKE_SUPER))
-#define pte_clear(ptep) ({ pte_val(*(ptep)) = 0; })
-
-#define pmd_none(pmd) (!pmd_val(pmd))
-#define pmd_bad(pmd) ((pmd_val(pmd) & _DESCTYPE_MASK) != _PAGE_TABLE)
-#define pmd_present(pmd) (pmd_val(pmd) & _PAGE_TABLE)
-#define pmd_clear(pmdp) ({ \
- unsigned long *__ptr = pmdp->pmd; \
- short __i = 16; \
- while (--__i >= 0) \
- *__ptr++ = 0; \
-})
-
-#define pgd_none(pgd) (!pgd_val(pgd))
-#define pgd_bad(pgd) ((pgd_val(pgd) & _DESCTYPE_MASK) != _PAGE_TABLE)
-#define pgd_present(pgd) (pgd_val(pgd) & _PAGE_TABLE)
-#define pgd_clear(pgdp) ({ pgd_val(*pgdp) = 0; })
-
-/* Permanent address of a page. */
-#define page_address(page) ((page)->virtual)
-#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
-#define pte_page(pte) (mem_map+((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT))
-
-#define pte_ERROR(e) \
- printk("%s:%d: bad pte %p(%08lx).\n", __FILE__, __LINE__, &(e), pte_val(e))
-#define pmd_ERROR(e) \
- printk("%s:%d: bad pmd %p(%08lx).\n", __FILE__, __LINE__, &(e), pmd_val(e))
-#define pgd_ERROR(e) \
- printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
-
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-extern inline int pte_read(pte_t pte) { return 1; }
-extern inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_RONLY); }
-extern inline int pte_exec(pte_t pte) { return 1; }
-extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
-extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
-
-extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_RONLY; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte) { return pte; }
-extern inline pte_t pte_exprotect(pte_t pte) { return pte; }
-extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) &= ~_PAGE_RONLY; return pte; }
-extern inline pte_t pte_mkread(pte_t pte) { return pte; }
-extern inline pte_t pte_mkexec(pte_t pte) { return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_mknocache(pte_t pte)
-{
- pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_pgtable_cachemode;
- return pte;
-}
-extern inline pte_t pte_mkcache(pte_t pte) { pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode; return pte; }
-
-#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
-
-#define pgd_index(address) ((address) >> PGDIR_SHIFT)
-
-/* to find an entry in a page-table-directory */
-extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
-{
- return mm->pgd + pgd_index(address);
-}
-
-#define swapper_pg_dir kernel_pg_dir
-extern pgd_t kernel_pg_dir[128];
-
-extern inline pgd_t * pgd_offset_k(unsigned long address)
-{
- return kernel_pg_dir + (address >> PGDIR_SHIFT);
-}
-
-
-/* Find an entry in the second-level page table.. */
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
-{
- return (pmd_t *)__pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PMD-1));
-}
-
-/* Find an entry in the third-level page table.. */
-extern inline pte_t * pte_offset(pmd_t * pmdp, unsigned long address)
-{
- return (pte_t *)__pmd_page(*pmdp) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
-}
-
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
-
-/* Prior to calling these routines, the page should have been flushed
- * from both the cache and ATC, or the CPU might not notice that the
- * cache setting for the page has been changed. -jskov
- */
-static inline void nocache_page (unsigned long vaddr)
-{
- if (CPU_IS_040_OR_060) {
- pgd_t *dir;
- pmd_t *pmdp;
- pte_t *ptep;
-
- dir = pgd_offset_k(vaddr);
- pmdp = pmd_offset(dir,vaddr);
- ptep = pte_offset(pmdp,vaddr);
- *ptep = pte_mknocache(*ptep);
- }
-}
-
-static inline void cache_page (unsigned long vaddr)
-{
- if (CPU_IS_040_OR_060) {
- pgd_t *dir;
- pmd_t *pmdp;
- pte_t *ptep;
-
- dir = pgd_offset_k(vaddr);
- pmdp = pmd_offset(dir,vaddr);
- ptep = pte_offset(pmdp,vaddr);
- *ptep = pte_mkcache(*ptep);
- }
-}
-
+#define SIZEOF_PTR_LOG2 2
/*
* Check if the addr/len goes up to the end of a physical
/*
* The m68k doesn't have any external MMU info: the kernel page
- * tables contain all the necessary information.
+ * tables contain all the necessary information. The Sun3 does, but
+ * they are updated on demand.
*/
extern inline void update_mmu_cache(struct vm_area_struct * vma,
unsigned long address, pte_t pte)
{
}
+#ifdef CONFIG_SUN3
+/* Macros to (de)construct the fake PTEs representing swap pages. */
+#define SWP_TYPE(x) ((x).val & 0x7F)
+#define SWP_OFFSET(x) (((x).val) >> 7)
+#define SWP_ENTRY(type,offset) ((swp_entry_t) { ((type) | ((offset) << 7)) })
+#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+#define swp_entry_to_pte(x) ((pte_t) { (x).val })
+
+#else
+
/* Encode and de-code a swap entry (must be !pte_none(e) && !pte_present(e)) */
#define SWP_TYPE(x) (((x).val >> 1) & 0xff)
#define SWP_OFFSET(x) ((x).val >> 10)
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
-#endif /* __ASSEMBLY__ */
+#endif CONFIG_SUN3
+
+#endif /* !__ASSEMBLY__ */
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
#define PageSkip(page) (0)
#define io_remap_page_range remap_page_range
+/* MMU-specific headers */
+
+#ifdef CONFIG_SUN3
+#include <asm/sun3_pgtable.h>
+#else
+#include <asm/motorola_pgtable.h>
+#endif
+
+#ifndef __ASSEMBLY__
#include <asm-generic/pgtable.h>
+#endif /* !__ASSEMBLY__ */
#endif /* _M68K_PGTABLE_H */
char raw_mode);
extern char q40kbd_unexpected_up(unsigned char keycode);
extern void q40kbd_leds(unsigned char leds);
-extern int q40kbd_is_sysrq(unsigned char keycode);
extern void q40kbd_init_hw(void);
extern unsigned char q40kbd_sysrq_xlate[128];
#define kbd_unexpected_up q40kbd_unexpected_up
#define kbd_leds q40kbd_leds
#define kbd_init_hw q40kbd_init_hw
-#define kbd_is_sysrq q40kbd_is_sysrq
#define kbd_sysrq_xlate q40kbd_sysrq_xlate
#include <asm/atomic.h>
-#define local_bh_disable() (local_bh_count(smp_processor_id())++)
-#define local_bh_enable() (local_bh_count(smp_processor_id())--)
+#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0)
+#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0)
-#define in_softirq() (local_bh_count != 0)
+#define local_bh_disable() cpu_bh_disable(smp_processor_id())
+#define local_bh_enable() cpu_bh_enable(smp_processor_id())
-/* These are for the irq's testing the lock */
-#define softirq_trylock(cpu) (local_bh_count(cpu) ? 0 : (local_bh_count(cpu)=1))
-#define softirq_endlock(cpu) (local_bh_count(cpu) = 0)
-#define synchronize_bh() barrier()
+#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
#endif
#ifndef __M68K_SPINLOCK_H
#define __M68K_SPINLOCK_H
-#error "m68k doesn't do SMP"
+#error "m68k doesn't do SMP yet"
#endif
struct stat64 {
unsigned char __pad0[6];
unsigned short st_dev;
+ unsigned char __pad1[4];
- unsigned long long st_ino;
+#define STAT64_HAS_BROKEN_ST_INO 1
+ unsigned long __st_ino;
unsigned int st_mode;
unsigned int st_nlink;
unsigned long st_uid;
unsigned long st_gid;
+ unsigned char __pad2[6];
unsigned short st_rdev;
- unsigned char __pad3[10];
+ unsigned char __pad3[4];
long long st_size;
unsigned long st_blksize;
- unsigned long st_blocks; /* Number 512-byte blocks allocated. */
unsigned long __pad4; /* future possible st_blocks high bits */
+ unsigned long st_blocks; /* Number 512-byte blocks allocated. */
unsigned long st_atime;
unsigned long __pad5;
unsigned long st_ctime;
unsigned long __pad7; /* will be high 32 bits of ctime someday */
- unsigned long __unused1;
- unsigned long __unused2;
+ unsigned long long st_ino;
};
#endif /* _M68K_STAT_H */
--- /dev/null
+/* sun3_pgalloc.h --
+ * reorganization around 2.3.39, routines moved from sun3_pgtable.h
+ *
+ * moved 1/26/2000 Sam Creasey
+ */
+
+#ifndef _SUN3_PGALLOC_H
+#define _SUN3_PGALLOC_H
+
+/* Pagetable caches. */
+//todo: should implement for at least ptes. --m
+#define pgd_quicklist ((unsigned long *) 0)
+#define pmd_quicklist ((unsigned long *) 0)
+#define pte_quicklist ((unsigned long *) 0)
+#define pgtable_cache_size (0L)
+
+/* Allocation and deallocation of various flavours of pagetables. */
+extern inline int free_pmd_fast (pmd_t *pmdp) { return 0; }
+extern inline int free_pmd_slow (pmd_t *pmdp) { return 0; }
+extern inline pmd_t *get_pmd_fast (void) { return (pmd_t *) 0; }
+
+//todo: implement the following properly.
+#define get_pte_fast() ((pte_t *) 0)
+#define get_pte_slow pte_alloc
+#define free_pte_fast(pte)
+#define free_pte_slow pte_free
+
+/* FIXME - when we get this compiling */
+/* erm, now that it's compiling, what do we do with it? */
+#define _KERNPG_TABLE 0
+
+extern inline void pte_free_kernel(pte_t * pte)
+{
+ free_page((unsigned long) pte);
+}
+
+extern const char bad_pmd_string[];
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+ address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+ if (pmd_none(*pmd)) {
+ pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (page) {
+ pmd_val(*pmd) = _KERNPG_TABLE + __pa(page);
+ return page + address;
+ }
+ pmd_val(*pmd) = _KERNPG_TABLE + __pa((unsigned long)BAD_PAGETABLE);
+ return NULL;
+ }
+ free_page((unsigned long) page);
+ }
+ if (pmd_bad(*pmd)) {
+ printk(bad_pmd_string, pmd_val(*pmd));
+ printk("at kernel pgd off %08x\n", (unsigned int)pmd);
+ pmd_val(*pmd) = _KERNPG_TABLE + __pa((unsigned long)BAD_PAGETABLE);
+ return NULL;
+ }
+ return (pte_t *) __pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free_kernel(pmd_t * pmd)
+{
+// pmd_val(*pmd) = 0;
+}
+
+extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
+{
+ return (pmd_t *) pgd;
+}
+
+extern inline void pte_free(pte_t * pte)
+{
+ free_page((unsigned long) pte);
+}
+
+extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+{
+ address = (address >> (PAGE_SHIFT-2)) & 4*(PTRS_PER_PTE - 1);
+
+repeat:
+ if (pmd_none(*pmd))
+ goto getnew;
+ if (pmd_bad(*pmd))
+ goto fix;
+ return (pte_t *) (__pmd_page(*pmd) + address);
+
+getnew:
+{
+ unsigned long page = __get_free_page(GFP_KERNEL);
+ if (!pmd_none(*pmd))
+ goto freenew;
+ if (!page)
+ goto oom;
+ memset((void *)page, 0, PAGE_SIZE);
+// pmd_val(*pmd) = SUN3_PMD_MAGIC + __pa(page);
+ pmd_val(*pmd) = __pa(page);
+ return (pte_t *) (page + address);
+freenew:
+ free_page(page);
+ goto repeat;
+}
+
+fix:
+ printk(bad_pmd_string, pmd_val(*pmd));
+ printk("in normal pgd offset %08x\n", (unsigned int)pmd);
+oom:
+// pmd_val(*pmd) = SUN3_PMD_MAGIC + __pa(BAD_PAGETABLE);
+ pmd_val(*pmd) = __pa(BAD_PAGETABLE);
+ return NULL;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free(pmd_t * pmd)
+{
+ pmd_val(*pmd) = 0;
+}
+
+extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+ return (pmd_t *) pgd;
+}
+
+extern inline void pgd_free(pgd_t * pgd)
+{
+ free_page((unsigned long) pgd);
+}
+
+extern inline pgd_t * pgd_alloc(void)
+{
+ pgd_t *new_pgd;
+
+ new_pgd = (pgd_t *)get_free_page(GFP_KERNEL);
+ memcpy(new_pgd, swapper_pg_dir, PAGE_SIZE);
+ memset(new_pgd, 0, (PAGE_OFFSET >> PGDIR_SHIFT));
+ return new_pgd;
+}
+
+/* FIXME: the sun3 doesn't have a page table cache!
+ (but the motorola routine should just return 0) */
+
+extern int do_check_pgt_cache(int, int);
+
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+}
+
+/* Reserved PMEGs. */
+extern char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
+extern unsigned long pmeg_vaddr[SUN3_PMEGS_NUM];
+extern unsigned char pmeg_alloc[SUN3_PMEGS_NUM];
+extern unsigned char pmeg_ctx[SUN3_PMEGS_NUM];
+
+/* Flush all userspace mappings one by one... (why no flush command,
+ sun?) */
+static inline void flush_tlb_all(void)
+{
+ unsigned long addr;
+ unsigned char ctx, oldctx;
+
+ oldctx = sun3_get_context();
+ for(addr = 0x00000000; addr < TASK_SIZE; addr += SUN3_PMEG_SIZE) {
+ for(ctx = 0; ctx < 8; ctx++) {
+ sun3_put_context(ctx);
+ sun3_put_segmap(addr, SUN3_INVALID_PMEG);
+ }
+ }
+
+ sun3_put_context(oldctx);
+ /* erase all of the userspace pmeg maps, we've clobbered them
+ all anyway */
+ for(addr = 0; addr < SUN3_INVALID_PMEG; addr++) {
+ if(pmeg_alloc[addr] == 1) {
+ pmeg_alloc[addr] = 0;
+ pmeg_ctx[addr] = 0;
+ pmeg_vaddr[addr] = 0;
+ }
+ }
+
+}
+
+/* Clear user TLB entries within the context named in mm */
+static inline void flush_tlb_mm (struct mm_struct *mm)
+{
+ unsigned char oldctx;
+ unsigned char seg;
+ unsigned long i;
+
+ oldctx = sun3_get_context();
+ sun3_put_context(mm->context);
+
+ for(i = 0; i < TASK_SIZE; i += SUN3_PMEG_SIZE) {
+ seg = sun3_get_segmap(i);
+ if(seg == SUN3_INVALID_PMEG)
+ continue;
+
+ sun3_put_segmap(i, SUN3_INVALID_PMEG);
+ pmeg_alloc[seg] = 0;
+ pmeg_ctx[seg] = 0;
+ pmeg_vaddr[seg] = 0;
+ }
+
+ sun3_put_context(oldctx);
+
+}
+
+/* Flush a single TLB page. In this case, we're limited to flushing a
+ single PMEG */
+static inline void flush_tlb_page (struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ unsigned char oldctx;
+ unsigned char i;
+
+ oldctx = sun3_get_context();
+ sun3_put_context(vma->vm_mm->context);
+ addr &= ~SUN3_PMEG_MASK;
+ if((i = sun3_get_segmap(addr)) != SUN3_INVALID_PMEG)
+ {
+ pmeg_alloc[i] = 0;
+ pmeg_ctx[i] = 0;
+ pmeg_vaddr[i] = 0;
+ sun3_put_segmap (addr, SUN3_INVALID_PMEG);
+ }
+ sun3_put_context(oldctx);
+
+}
+/* Flush a range of pages from TLB. */
+
+static inline void flush_tlb_range (struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ unsigned char seg, oldctx;
+
+ start &= ~SUN3_PMEG_MASK;
+
+ oldctx = sun3_get_context();
+ sun3_put_context(mm->context);
+
+ while(start < end)
+ {
+ if((seg = sun3_get_segmap(start)) == SUN3_INVALID_PMEG)
+ goto next;
+ if(pmeg_ctx[seg] == mm->context) {
+ pmeg_alloc[seg] = 0;
+ pmeg_ctx[seg] = 0;
+ pmeg_vaddr[seg] = 0;
+ }
+ sun3_put_segmap(start, SUN3_INVALID_PMEG);
+ next:
+ start += SUN3_PMEG_SIZE;
+ }
+}
+
+/* Flush kernel page from TLB. */
+static inline void flush_tlb_kernel_page (unsigned long addr)
+{
+ sun3_put_segmap (addr & ~(SUN3_PMEG_SIZE - 1), SUN3_INVALID_PMEG);
+}
+
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+}
+
+#endif /* SUN3_PGALLOC_H */
--- /dev/null
+#ifndef _SUN3_PGTABLE_H
+#define _SUN3_PGTABLE_H
+
+#include <asm/sun3mmu.h>
+
+#ifndef __ASSEMBLY__
+#include <asm/virtconvert.h>
+#include <linux/linkage.h>
+
+/*
+ * This file contains all the things which change drastically for the sun3
+ * pagetable stuff, to avoid making too much of a mess of the generic m68k
+ * `pgtable.h'; this should only be included from the generic file. --m
+ */
+
+/* For virtual address to physical address conversion */
+#define VTOP(addr) __pa(addr)
+#define PTOV(addr) __va(addr)
+
+
+#endif /* !__ASSEMBLY__ */
+
+/* These need to be defined for compatibility although the sun3 doesn't use them */
+#define _PAGE_NOCACHE030 0x040
+#define _CACHEMASK040 (~0x060)
+#define _PAGE_NOCACHE_S 0x040
+
+/* Page protection values within PTE. */
+#define SUN3_PAGE_VALID (0x80000000)
+#define SUN3_PAGE_WRITEABLE (0x40000000)
+#define SUN3_PAGE_SYSTEM (0x20000000)
+#define SUN3_PAGE_NOCACHE (0x10000000)
+#define SUN3_PAGE_ACCESSED (0x02000000)
+#define SUN3_PAGE_MODIFIED (0x01000000)
+
+
+/* Externally used page protection values. */
+#define _PAGE_PRESENT (SUN3_PAGE_VALID)
+#define _PAGE_ACCESSED (SUN3_PAGE_ACCESSED)
+
+/* Compound page protection values. */
+//todo: work out which ones *should* have SUN3_PAGE_NOCACHE and fix...
+// is it just PAGE_KERNEL and PAGE_SHARED?
+#define PAGE_NONE __pgprot(SUN3_PAGE_VALID \
+ | SUN3_PAGE_ACCESSED \
+ | SUN3_PAGE_NOCACHE)
+#define PAGE_SHARED __pgprot(SUN3_PAGE_VALID \
+ | SUN3_PAGE_WRITEABLE \
+ | SUN3_PAGE_ACCESSED \
+ | SUN3_PAGE_NOCACHE)
+#define PAGE_COPY __pgprot(SUN3_PAGE_VALID \
+ | SUN3_PAGE_ACCESSED \
+ | SUN3_PAGE_NOCACHE)
+#define PAGE_READONLY __pgprot(SUN3_PAGE_VALID \
+ | SUN3_PAGE_ACCESSED \
+ | SUN3_PAGE_NOCACHE)
+#define PAGE_KERNEL __pgprot(SUN3_PAGE_VALID \
+ | SUN3_PAGE_WRITEABLE \
+ | SUN3_PAGE_SYSTEM \
+ | SUN3_PAGE_NOCACHE \
+ | SUN3_PAGE_ACCESSED \
+ | SUN3_PAGE_MODIFIED)
+#define PAGE_INIT __pgprot(SUN3_PAGE_VALID \
+ | SUN3_PAGE_WRITEABLE \
+ | SUN3_PAGE_SYSTEM \
+ | SUN3_PAGE_NOCACHE)
+
+/*
+ * Page protections for initialising protection_map. The sun3 has only two
+ * protection settings, valid (implying read and execute) and writeable. These
+ * are as close as we can get...
+ */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY
+#define __P100 PAGE_READONLY
+#define __P101 PAGE_READONLY
+#define __P110 PAGE_COPY
+#define __P111 PAGE_COPY
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_READONLY
+#define __S101 PAGE_READONLY
+#define __S110 PAGE_SHARED
+#define __S111 PAGE_SHARED
+
+/* Use these fake page-protections on PMDs. */
+#define SUN3_PMD_VALID (0x00000001)
+#define SUN3_PMD_MASK (0x0000003F)
+#define SUN3_PMD_MAGIC (0x0000002B)
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define __mk_pte(page, pgprot) \
+({ pte_t __pte; pte_val(__pte) = (__pa(page) >> PAGE_SHIFT) | pgprot_val(pgprot); __pte; })
+#define mk_pte(page, pgprot) __mk_pte(page_address(page), (pgprot))
+#define mk_pte_phys(physpage, pgprot) \
+({ pte_t __pte; pte_val(__pte) = ((physpage) >> PAGE_SHIFT) | pgprot_val(pgprot); __pte; })
+extern inline pte_t pte_modify (pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & SUN3_PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+#define pmd_set(pmdp,ptep) do {} while (0)
+
+extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{ pgd_val(*pgdp) = virt_to_phys(pmdp); }
+
+#define __pte_page(pte) \
+((unsigned long) __va ((pte_val (pte) & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT))
+#define __pmd_page(pmd) \
+((unsigned long) __va (pmd_val (pmd) & PAGE_MASK))
+
+extern inline int pte_none (pte_t pte) { return !pte_val (pte); }
+extern inline int pte_present (pte_t pte) { return pte_val (pte) & SUN3_PAGE_VALID; }
+extern inline void pte_clear (pte_t *ptep) { pte_val (*ptep) = 0; }
+
+/* FIXME: this is only a guess */
+#define pte_pagenr(pte) ((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT)
+/* Permanent address of a page. */
+#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; })
+#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
+#define pte_page(pte) (mem_map+pte_pagenr(pte))
+
+
+extern inline int pmd_none2 (pmd_t *pmd) { return !pmd_val (*pmd); }
+#define pmd_none(pmd) pmd_none2(&(pmd))
+//extern inline int pmd_bad (pmd_t pmd) { return (pmd_val (pmd) & SUN3_PMD_MASK) != SUN3_PMD_MAGIC; }
+extern inline int pmd_bad2 (pmd_t *pmd) { return 0; }
+#define pmd_bad(pmd) pmd_bad2(&(pmd))
+extern inline int pmd_present2 (pmd_t *pmd) { return pmd_val (*pmd) & SUN3_PMD_VALID; }
+#define pmd_present(pmd) pmd_present2(&(pmd))
+extern inline void pmd_clear (pmd_t *pmdp) { pmd_val (*pmdp) = 0; }
+
+extern inline int pgd_none (pgd_t pgd) { return 0; }
+extern inline int pgd_bad (pgd_t pgd) { return 0; }
+extern inline int pgd_present (pgd_t pgd) { return 0; }
+extern inline void pgd_clear (pgd_t *pgdp) {}
+
+
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not...
+ * [we have the full set here even if they don't change from m68k]
+ */
+extern inline int pte_read(pte_t pte) { return 1; }
+extern inline int pte_write(pte_t pte) { return pte_val(pte) & SUN3_PAGE_WRITEABLE; }
+extern inline int pte_exec(pte_t pte) { return 1; }
+extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & SUN3_PAGE_MODIFIED; }
+extern inline int pte_young(pte_t pte) { return pte_val(pte) & SUN3_PAGE_ACCESSED; }
+
+extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~SUN3_PAGE_WRITEABLE; return pte; }
+extern inline pte_t pte_rdprotect(pte_t pte) { return pte; }
+extern inline pte_t pte_exprotect(pte_t pte) { return pte; }
+extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~SUN3_PAGE_MODIFIED; return pte; }
+extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~SUN3_PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= SUN3_PAGE_WRITEABLE; return pte; }
+extern inline pte_t pte_mkread(pte_t pte) { return pte; }
+extern inline pte_t pte_mkexec(pte_t pte) { return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= SUN3_PAGE_MODIFIED; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= SUN3_PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_mknocache(pte_t pte) { pte_val(pte) |= SUN3_PAGE_NOCACHE; return pte; }
+// use this version when caches work...
+//extern inline pte_t pte_mkcache(pte_t pte) { pte_val(pte) &= SUN3_PAGE_NOCACHE; return pte; }
+// until then, use:
+extern inline pte_t pte_mkcache(pte_t pte) { return pte; }
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+extern pgd_t kernel_pg_dir[PTRS_PER_PGD];
+
+/* Find an entry in a pagetable directory. */
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+
+#define pgd_offset(mm, address) \
+((mm)->pgd + pgd_index(address))
+
+/* Find an entry in a kernel pagetable directory. */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* Find an entry in the second-level pagetable. */
+extern inline pmd_t *pmd_offset (pgd_t *pgd, unsigned long address)
+{
+ return (pmd_t *) pgd;
+}
+
+/* Find an entry in the third-level pagetable. */
+#define pte_offset(pmd, address) \
+((pte_t *) __pmd_page (*pmd) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE-1)))
+
+/* Disable caching for page at given kernel virtual address. */
+static inline void nocache_page (unsigned long vaddr)
+{
+ /* Don't think this is required on sun3. --m */
+}
+
+/* Enable caching for page at given kernel virtual address. */
+static inline void cache_page (unsigned long vaddr)
+{
+ /* Don't think this is required on sun3. --m */
+}
+
+
+
+#endif /* !__ASSEMBLY__ */
+#endif /* !_SUN3_PGTABLE_H */
#include <linux/config.h> /* get configuration macros */
#include <linux/linkage.h>
+#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/entry.h>
#define sti() __sti()
#define save_flags(x) __save_flags(x)
#define restore_flags(x) __restore_flags(x)
-
+#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
/*
* Force strict CPU ordering.
* Not really required on m68k...
*/
-#define nop() asm volatile ("nop"::)
-#define mb() asm volatile ("" : : :"memory")
-#define rmb() asm volatile ("" : : :"memory")
-#define wmb() asm volatile ("" : : :"memory")
+#define nop() do { asm volatile ("nop"); barrier(); } while (0)
+#define mb() barrier()
+#define rmb() barrier()
+#define wmb() barrier()
#define set_mb(var, value) do { xchg(&var, value); } while (0)
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+#define smp_mb() barrier()
+#define smp_rmb() barrier()
+#define smp_wmb() barrier()
+
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
#define tas(ptr) (xchg((ptr),1))
#define BITS_PER_LONG 32
+/* DMA addresses are 32-bits wide */
+
+typedef u32 dma_addr_t;
+
#endif /* __KERNEL__ */
#endif /* _M68K_TYPES_H */
/* fsync.c */
extern int ext2_sync_file (struct file *, struct dentry *, int);
+extern int ext2_fsync_inode (struct inode *, int);
/* ialloc.c */
extern struct inode * ext2_new_inode (const struct inode *, int, int *);
unsigned long b_rsector; /* Real buffer location on disk */
wait_queue_head_t b_wait;
+
+ struct inode * b_inode;
+ struct list_head b_inode_buffers; /* doubly linked list of inode dirty buffers */
};
typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
struct list_head i_hash;
struct list_head i_list;
struct list_head i_dentry;
+
+ struct list_head i_dirty_buffers;
unsigned long i_ino;
atomic_t i_count;
};
/* Inode state bits.. */
-#define I_DIRTY 1
-#define I_LOCK 2
-#define I_FREEING 4
-#define I_CLEAR 8
+#define I_DIRTY_SYNC 1 /* Not dirty enough for O_DATASYNC */
+#define I_DIRTY_DATASYNC 2 /* Data-related inode changes pending */
+#define I_LOCK 4
+#define I_FREEING 8
+#define I_CLEAR 16
+
+#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC)
-extern void __mark_inode_dirty(struct inode *);
+extern void __mark_inode_dirty(struct inode *, int);
static inline void mark_inode_dirty(struct inode *inode)
{
- if (!(inode->i_state & I_DIRTY))
- __mark_inode_dirty(inode);
+ if ((inode->i_state & I_DIRTY) != I_DIRTY)
+ __mark_inode_dirty(inode, I_DIRTY);
+}
+
+static inline void mark_inode_dirty_sync(struct inode *inode)
+{
+ if (!(inode->i_state & I_DIRTY_SYNC))
+ __mark_inode_dirty(inode, I_DIRTY_SYNC);
}
struct fown_struct {
bh->b_end_io(bh, 0);
}
+extern void buffer_insert_inode_queue(struct buffer_head *, struct inode *);
+static inline void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
+{
+ mark_buffer_dirty(bh);
+ buffer_insert_inode_queue(bh, inode);
+}
+
extern void balance_dirty(kdev_t);
extern int check_disk_change(kdev_t);
extern int invalidate_inodes(struct super_block *);
extern void invalidate_inode_pages(struct inode *);
+extern void invalidate_inode_buffers(struct inode *);
#define invalidate_buffers(dev) __invalidate_buffers((dev), 0)
#define destroy_buffers(dev) __invalidate_buffers((dev), 1)
extern void __invalidate_buffers(kdev_t dev, int);
extern void write_inode_now(struct inode *, int);
extern void sync_dev(kdev_t);
extern int fsync_dev(kdev_t);
+extern int fsync_inode_buffers(struct inode *);
+extern int osync_inode_buffers(struct inode *);
+extern int inode_has_buffers(struct inode *);
extern void sync_supers(kdev_t);
extern int bmap(struct inode *, int);
extern int notify_change(struct dentry *, struct iattr *);
extern int file_fsync(struct file *, struct dentry *, int);
extern int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsigned long end_idx);
+extern int generic_osync_inode(struct inode *, int);
extern int inode_change_ok(struct inode *, struct iattr *);
extern void inode_setattr(struct inode *, struct iattr *);
struct resource *parent, *sibling, *child;
};
+struct resource_list {
+ struct resource_list *next;
+ struct resource *res;
+ struct pci_dev *dev;
+};
+
/*
* IO resources have these defined flags.
*/
#define IORESOURCE_CACHEABLE 0x00004000
#define IORESOURCE_RANGELENGTH 0x00008000
#define IORESOURCE_SHADOWABLE 0x00010000
+#define IORESOURCE_BUS_HAS_VGA 0x00080000
#define IORESOURCE_UNSET 0x20000000
#define IORESOURCE_AUTO 0x40000000
ATTRIB_NORET;
extern unsigned long simple_strtoul(const char *,char **,unsigned int);
extern long simple_strtol(const char *,char **,unsigned int);
+extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
+extern long long simple_strtoll(const char *,char **,unsigned int);
extern int sprintf(char * buf, const char * fmt, ...);
extern int vsprintf(char *buf, const char *, va_list);
extern int get_option(char **str, int *pint);
int pci_set_power_state(struct pci_dev *dev, int state);
int pci_assign_resource(struct pci_dev *dev, int i);
-/* Helper functions for low-level code (drivers/pci/setup.c) */
+/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
int pci_claim_resource(struct pci_dev *, int);
void pci_assign_unassigned_resources(void);
-void pdev_assign_unassigned_resources(struct pci_dev *dev);
-void pci_set_bus_ranges(void);
+void pdev_enable_device(struct pci_dev *);
+void pdev_sort_resources(struct pci_dev *, struct resource_list *, u32);
+unsigned long pci_bridge_check_io(struct pci_dev *);
void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
int (*)(struct pci_dev *, u8, u8));
/* Vendors and devices. Sort key: vendor first, device next. */
+/* Should be Dynalink - same company? */
+#define PCI_VENDOR_ID_ASUSCOM 0x0675
+#define PCI_DEVICE_ID_ASUSCOM_TA1 0x1702
+
#define PCI_VENDOR_ID_COMPAQ 0x0e11
#define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508
#define PCI_DEVICE_ID_COMPAQ_1280 0x3033
#define PCI_VENDOR_ID_NS 0x100b
#define PCI_DEVICE_ID_NS_87415 0x0002
-#define PCI_DEVICE_ID_NS_87560_LIO 0x000e
-#define PCI_DEVICE_ID_NS_87560_USB 0x0012
+#define PCI_DEVICE_ID_NS_87560_LIO 0x000e
+#define PCI_DEVICE_ID_NS_87560_USB 0x0012
#define PCI_DEVICE_ID_NS_87410 0xd001
#define PCI_VENDOR_ID_TSENG 0x100c
#define PCI_DEVICE_ID_IBM_405GP 0x0156
#define PCI_DEVICE_ID_IBM_MPIC_2 0xffff
+#define PCI_VENDOR_ID_COMPEX2 0x101a // pci.ids says "AT&T GIS (NCR)"
+#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005
+
#define PCI_VENDOR_ID_WD 0x101c
#define PCI_DEVICE_ID_WD_7197 0x3296
+#define PCI_VENDOR_ID_AMI 0x101e
+#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960
+#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010
+#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060
+
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
#define PCI_DEVICE_ID_AMD_VIPER_740C 0x740C
#define PCI_VENDOR_ID_TRIDENT 0x1023
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001
#define PCI_DEVICE_ID_TRIDENT_9320 0x9320
#define PCI_DEVICE_ID_TRIDENT_9388 0x9388
#define PCI_DEVICE_ID_TRIDENT_9397 0x9397
#define PCI_DEVICE_ID_MATROX_MIL_2 0x051b
#define PCI_DEVICE_ID_MATROX_MIL_2_AGP 0x051f
#define PCI_DEVICE_ID_MATROX_MGA_IMP 0x0d10
-#define PCI_DEVICE_ID_MATROX_G100_MM 0x1000
-#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
-#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520
-#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
+#define PCI_DEVICE_ID_MATROX_G100_MM 0x1000
+#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
+#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520
+#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
#define PCI_DEVICE_ID_MATROX_G400 0x0525
#define PCI_DEVICE_ID_MATROX_VIA 0x4536
#define PCI_DEVICE_ID_PCTECH_SAMURAI_1 0x3010
#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
-#define PCI_VENDOR_ID_DPT 0x1044
-#define PCI_DEVICE_ID_DPT 0xa400
+#define PCI_VENDOR_ID_DPT 0x1044
+#define PCI_DEVICE_ID_DPT 0xa400
#define PCI_VENDOR_ID_OPTI 0x1045
#define PCI_DEVICE_ID_OPTI_92C178 0xc178
#define PCI_DEVICE_ID_OPTI_82C861 0xc861
#define PCI_DEVICE_ID_OPTI_82C825 0xd568
+#define PCI_VENDOR_ID_ELSA 0x1048
+#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000
+#define PCI_DEVICE_ID_ELSA_QS3000 0x3000
+
#define PCI_VENDOR_ID_SGS 0x104a
#define PCI_DEVICE_ID_SGS_2000 0x0008
#define PCI_DEVICE_ID_SGS_1764 0x0009
#define PCI_DEVICE_ID_TI_1251B 0xac1f
#define PCI_DEVICE_ID_TI_1420 0xac51
+#define PCI_VENDOR_ID_SONY 0x104d
+#define PCI_DEVICE_ID_SONY_CXD3222 0x8039
#define PCI_VENDOR_ID_OAK 0x104e
#define PCI_DEVICE_ID_OAK_OTI107 0x0107
#define PCI_VENDOR_ID_WINBOND2 0x1050
#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940
#define PCI_DEVICE_ID_WINBOND2_89C940F 0x5a5a
+#define PCI_DEVICE_ID_WINBOND2_6692 0x6692
#define PCI_VENDOR_ID_EFAR 0x1055
#define PCI_DEVICE_ID_EFAR_SLC90E66_1 0x9130
#define PCI_VENDOR_ID_LEADTEK 0x107d
#define PCI_DEVICE_ID_LEADTEK_805 0x0000
-#define PCI_VENDOR_ID_INTERPHASE 0x107e
+#define PCI_VENDOR_ID_INTERPHASE 0x107e
#define PCI_DEVICE_ID_INTERPHASE_5526 0x0004
#define PCI_DEVICE_ID_INTERPHASE_55x6 0x0005
+#define PCI_DEVICE_ID_INTERPHASE_5575 0x0008
#define PCI_VENDOR_ID_CONTAQ 0x1080
#define PCI_DEVICE_ID_CONTAQ_82C599 0x0600
#define PCI_VENDOR_ID_BROOKTREE 0x109e
#define PCI_DEVICE_ID_BROOKTREE_848 0x0350
#define PCI_DEVICE_ID_BROOKTREE_849A 0x0351
-#define PCI_DEVICE_ID_BROOKTREE_878_1 0x036e
-#define PCI_DEVICE_ID_BROOKTREE_878 0x0878
+#define PCI_DEVICE_ID_BROOKTREE_878_1 0x036e
+#define PCI_DEVICE_ID_BROOKTREE_878 0x0878
#define PCI_DEVICE_ID_BROOKTREE_8474 0x8474
#define PCI_VENDOR_ID_SIERRA 0x10a8
#define PCI_DEVICE_ID_DATABOOK_87144 0xb106
#define PCI_VENDOR_ID_PLX 0x10b5
-#define PCI_VENDOR_ID_PLX_ROMULUS 0x106a
+#define PCI_DEVICE_ID_PLX_R685 0x1030
+#define PCI_DEVICE_ID_PLX_ROMULUS 0x106a
#define PCI_DEVICE_ID_PLX_SPCOM800 0x1076
#define PCI_DEVICE_ID_PLX_1077 0x1077
#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103
+#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151
+#define PCI_DEVICE_ID_PLX_R753 0x1152
#define PCI_DEVICE_ID_PLX_9050 0x9050
#define PCI_DEVICE_ID_PLX_9060 0x9060
#define PCI_DEVICE_ID_PLX_9060ES 0x906E
#define PCI_DEVICE_ID_AL_M5229 0x5229
#define PCI_DEVICE_ID_AL_M5237 0x5237
#define PCI_DEVICE_ID_AL_M5243 0x5243
+#define PCI_DEVICE_ID_AL_M5451 0x5451
#define PCI_DEVICE_ID_AL_M7101 0x7101
#define PCI_VENDOR_ID_MITSUBISHI 0x10ba
#define PCI_VENDOR_ID_SURECOM 0x10bd
#define PCI_DEVICE_ID_SURECOM_NE34 0x0e34
-#define PCI_VENDOR_ID_NEOMAGIC 0x10c8
+#define PCI_VENDOR_ID_NEOMAGIC 0x10c8
#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2070 0x0001
#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128V 0x0002
#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZV 0x0003
#define PCI_DEVICE_ID_INIT_320P 0x9100
#define PCI_DEVICE_ID_INIT_360P 0x9500
+#define PCI_VENDOR_ID_CREATIVE 0x1102 // duplicate: ECTIVA
+#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
+
+#define PCI_VENDOR_ID_ECTIVA 0x1102 // duplicate: CREATIVE
+#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938
+
#define PCI_VENDOR_ID_TTI 0x1103
#define PCI_DEVICE_ID_TTI_HPT343 0x0003
#define PCI_DEVICE_ID_TTI_HPT366 0x0004
#define PCI_DEVICE_ID_VIA_8633_1 0xB091
#define PCI_DEVICE_ID_VIA_8367_1 0xB099
-#define PCI_VENDOR_ID_SMC2 0x1113
-#define PCI_DEVICE_ID_SMC2_1211TX 0x1211
+#define PCI_VENDOR_ID_SMC2 0x1113
+#define PCI_DEVICE_ID_SMC2_1211TX 0x1211
#define PCI_VENDOR_ID_VORTEX 0x1119
#define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000
#define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000
#define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002
+#define PCI_VENDOR_ID_IDT 0x111d
+#define PCI_DEVICE_ID_IDT_IDT77201 0x0001
+
#define PCI_VENDOR_ID_FORE 0x1127
#define PCI_DEVICE_ID_FORE_PCA200PC 0x0210
#define PCI_DEVICE_ID_FORE_PCA200E 0x0300
#define PCI_DEVICE_ID_PHILIPS_SAA7145 0x7145
#define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146
+#define PCI_VENDOR_ID_EICON 0x1133
+#define PCI_DEVICE_ID_EICON_DIVA20PRO 0xe001
+#define PCI_DEVICE_ID_EICON_DIVA20 0xe002
+#define PCI_DEVICE_ID_EICON_DIVA20PRO_U 0xe003
+#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004
+#define PCI_DEVICE_ID_EICON_DIVA201 0xe005
+#define PCI_DEVICE_ID_EICON_MAESTRA 0xe010
+#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012
+#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013
+#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014
+
#define PCI_VENDOR_ID_CYCLONE 0x113c
#define PCI_DEVICE_ID_CYCLONE_SDK 0x0001
#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009
#define PCI_DEVICE_ID_SERVERWORKS_CIOB30 0x0010
#define PCI_DEVICE_ID_SERVERWORKS_CMIC_HE 0x0011
-#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201
-#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200
+#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201
+#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200
#define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211
#define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220
#define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005
#define PCI_DEVICE_ID_ARTOP_ATP860 0x0006
#define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007
+#define PCI_DEVICE_ID_ARTOP_AEC7610 0x8002
+#define PCI_DEVICE_ID_ARTOP_AEC7612UW 0x8010
+#define PCI_DEVICE_ID_ARTOP_AEC7612U 0x8020
+#define PCI_DEVICE_ID_ARTOP_AEC7612S 0x8030
+#define PCI_DEVICE_ID_ARTOP_AEC7612D 0x8040
+#define PCI_DEVICE_ID_ARTOP_AEC7612SUW 0x8050
+#define PCI_DEVICE_ID_ARTOP_8060 0x8060
#define PCI_VENDOR_ID_ZEITNET 0x1193
#define PCI_DEVICE_ID_ZEITNET_1221 0x0001
#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401
-#define PCI_VENDOR_ID_RP 0x11fe
-#define PCI_DEVICE_ID_RP32INTF 0x0001
-#define PCI_DEVICE_ID_RP8INTF 0x0002
-#define PCI_DEVICE_ID_RP16INTF 0x0003
-#define PCI_DEVICE_ID_RP4QUAD 0x0004
-#define PCI_DEVICE_ID_RP8OCTA 0x0005
-#define PCI_DEVICE_ID_RP8J 0x0006
-#define PCI_DEVICE_ID_RPP4 0x000A
-#define PCI_DEVICE_ID_RPP8 0x000B
-#define PCI_DEVICE_ID_RP8M 0x000C
+#define PCI_VENDOR_ID_RP 0x11fe
+#define PCI_DEVICE_ID_RP32INTF 0x0001
+#define PCI_DEVICE_ID_RP8INTF 0x0002
+#define PCI_DEVICE_ID_RP16INTF 0x0003
+#define PCI_DEVICE_ID_RP4QUAD 0x0004
+#define PCI_DEVICE_ID_RP8OCTA 0x0005
+#define PCI_DEVICE_ID_RP8J 0x0006
+#define PCI_DEVICE_ID_RPP4 0x000A
+#define PCI_DEVICE_ID_RPP8 0x000B
+#define PCI_DEVICE_ID_RP8M 0x000C
#define PCI_VENDOR_ID_CYCLADES 0x120e
#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100
#define PCI_VENDOR_ID_3DFX 0x121a
#define PCI_DEVICE_ID_3DFX_VOODOO 0x0001
#define PCI_DEVICE_ID_3DFX_VOODOO2 0x0002
-#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003
+#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003
#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005
#define PCI_VENDOR_ID_SIGMADES 0x1236
#define PCI_VENDOR_ID_CCUBE 0x123f
#define PCI_VENDOR_ID_AVM 0x1244
+#define PCI_DEVICE_ID_AVM_B1 0x0700
+#define PCI_DEVICE_ID_AVM_C4 0x0800
#define PCI_DEVICE_ID_AVM_A1 0x0a00
+#define PCI_DEVICE_ID_AVM_T1 0x1200
#define PCI_VENDOR_ID_DIPIX 0x1246
#define PCI_DEVICE_ID_OPTIBASE_VQUEST 0x2130
#define PCI_VENDOR_ID_ESS 0x125d
+#define PCI_DEVICE_ID_ESS_ESS1968 0x1968
#define PCI_DEVICE_ID_ESS_AUDIOPCI 0x1969
+#define PCI_DEVICE_ID_ESS_ESS1978 0x1978
#define PCI_VENDOR_ID_SATSAGEM 0x1267
+#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016
#define PCI_DEVICE_ID_SATSAGEM_PCR2101 0x5352
#define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b
#define PCI_VENDOR_ID_ENSONIQ 0x1274
#define PCI_DEVICE_ID_ENSONIQ_AUDIOPCI 0x5000
-#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
+#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
#define PCI_VENDOR_ID_ROCKWELL 0x127A
+/* formerly Platform Tech */
+#define PCI_VENDOR_ID_ESS_OLD 0x1285
+#define PCI_DEVICE_ID_ESS_ESS0100 0x0100
+
#define PCI_VENDOR_ID_ALTEON 0x12ae
#define PCI_DEVICE_ID_ALTEON_ACENIC 0x0001
#define PCI_SUBDEVICE_ID_CHASE_PCIRAS4 0xF001
#define PCI_SUBDEVICE_ID_CHASE_PCIRAS8 0xF010
+#define PCI_VENDOR_ID_AUREAL 0x12eb
+#define PCI_DEVICE_ID_AUREAL_VORTEX_1 0x0001
+#define PCI_DEVICE_ID_AUREAL_VORTEX_2 0x0002
+
#define PCI_VENDOR_ID_CBOARDS 0x1307
#define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001
#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062
+#define PCI_VENDOR_ID_DOMEX 0x134a
+#define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001
+
#define PCI_VENDOR_ID_QUATECH 0x135C
#define PCI_DEVICE_ID_QUATECH_QSC100 0x0010
#define PCI_DEVICE_ID_QUATECH_DSC100 0x0020
#define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401
#define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801
+#define PCI_VENDOR_ID_HYPERCOPE 0x1365
+#define PCI_DEVICE_ID_HYPERCOPE_PLX 0x9050
+
+#define PCI_VENDOR_ID_LMC 0x1376
+#define PCI_DEVICE_ID_LMC_HSSI 0x0003
+#define PCI_DEVICE_ID_LMC_DS3 0x0004
+#define PCI_DEVICE_ID_LMC_SSI 0x0005
+#define PCI_DEVICE_ID_LMC_T1 0x0006
+
#define PCI_VENDOR_ID_NETGEAR 0x1385
#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a
+#define PCI_VENDOR_ID_APPLICOM 0x1389
+#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001
+#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002
+#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003
+
+#define PCI_VENDOR_ID_MOXA 0x1393
+#define PCI_DEVICE_ID_MOXA_C104 0x1040
+#define PCI_DEVICE_ID_MOXA_C168 0x1680
+#define PCI_DEVICE_ID_MOXA_CP204J 0x2040
+#define PCI_DEVICE_ID_MOXA_C218 0x2180
+#define PCI_DEVICE_ID_MOXA_C320 0x3200
+
#define PCI_VENDOR_ID_3WARE 0x13C1
#define PCI_DEVICE_ID_3WARE_1000 0x1000
+#define PCI_VENDOR_ID_CMEDIA 0x13f6
+#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100
+#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101
+#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111
+#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112
+
#define PCI_VENDOR_ID_LAVA 0x1407
#define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */
#define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */
#define PCI_VENDOR_ID_TIMEDIA 0x1409
#define PCI_DEVICE_ID_TIMEDIA_1889 0x7168
-#define PCI_VENDOR_ID_OXSEMI 0x1415
-#define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501
+#define PCI_VENDOR_ID_OXSEMI 0x1415
+#define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501
#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x950A
#define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511
+#define PCI_VENDOR_ID_AIRONET 0x14b9
+#define PCI_DEVICE_ID_AIRONET_4800_1 0x0001
+#define PCI_DEVICE_ID_AIRONET_4800 0x4500 // values switched? see
+#define PCI_DEVICE_ID_AIRONET_4500 0x4800 // drivers/net/aironet4500_card.c
+
#define PCI_VENDOR_ID_TITAN 0x14D2
#define PCI_DEVICE_ID_TITAN_100 0xA001
#define PCI_DEVICE_ID_TITAN_200 0xA005
#define PCI_DEVICE_ID_INTEL_82441 0x1237
#define PCI_DEVICE_ID_INTEL_82380FB 0x124b
#define PCI_DEVICE_ID_INTEL_82439 0x1250
+#define PCI_DEVICE_ID_INTEL_80960_RP 0x1960
#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
#define PCI_VENDOR_ID_TIGERJET 0xe159
#define PCI_DEVICE_ID_TIGERJET_300 0x0001
+#define PCI_DEVICE_ID_TIGERJET_100 0x0002
#define PCI_VENDOR_ID_ARK 0xedd8
#define PCI_DEVICE_ID_ARK_STING 0xa091
struct file * fd_array[NR_OPEN_DEFAULT];
};
-#define INIT_FILES { \
- ATOMIC_INIT(1), \
- RW_LOCK_UNLOCKED, \
- NR_OPEN_DEFAULT, \
- __FD_SETSIZE, \
- 0, \
- &init_files.fd_array[0], \
- &init_files.close_on_exec_init, \
- &init_files.open_fds_init, \
- { { 0, } }, \
- { { 0, } }, \
- { NULL, } \
+#define INIT_FILES \
+{ \
+ count: ATOMIC_INIT(1), \
+ file_lock: RW_LOCK_UNLOCKED, \
+ max_fds: NR_OPEN_DEFAULT, \
+ max_fdset: __FD_SETSIZE, \
+ next_fd: 0, \
+ fd: &init_files.fd_array[0], \
+ close_on_exec: &init_files.close_on_exec_init, \
+ open_fds: &init_files.open_fds_init, \
+ close_on_exec_init: { { 0, } }, \
+ open_fds_init: { { 0, } }, \
+ fd_array: { NULL, } \
}
/* Maximum number of active map areas.. This is a random (large) number */
void * segments;
};
-#define INIT_MM(name) { \
- &init_mmap, NULL, NULL, \
- swapper_pg_dir, \
- ATOMIC_INIT(2), ATOMIC_INIT(1), 1, \
- __MUTEX_INITIALIZER(name.mmap_sem), \
- SPIN_LOCK_UNLOCKED, \
- 0, \
- 0, 0, 0, 0, \
- 0, 0, 0, \
- 0, 0, 0, 0, \
- 0, 0, 0, \
- 0, 0, 0, 0, NULL }
+#define INIT_MM(name) \
+{ \
+ mmap: &init_mmap, \
+ mmap_avl: NULL, \
+ mmap_cache: NULL, \
+ pgd: swapper_pg_dir, \
+ mm_users: ATOMIC_INIT(2), \
+ mm_count: ATOMIC_INIT(1), \
+ map_count: 1, \
+ mmap_sem: __MUTEX_INITIALIZER(name.mmap_sem), \
+ page_table_lock: SPIN_LOCK_UNLOCKED, \
+ segments: NULL \
+}
struct signal_struct {
atomic_t count;
};
-#define INIT_SIGNALS { \
- ATOMIC_INIT(1), \
- { {{0,}}, }, \
- SPIN_LOCK_UNLOCKED }
+#define INIT_SIGNALS { \
+ count: ATOMIC_INIT(1), \
+ action: { {{0,}}, }, \
+ siglock: SPIN_LOCK_UNLOCKED \
+}
/*
* Some day this will be a full-fledged user tracking system..
/* Ok, that's about all the sanity we can stomach; copy the rest. */
- if (copy_from_user(mod+1, mod_user+1, mod->size-sizeof(*mod))) {
+ if (copy_from_user((char *)mod+mod_user_size,
+ (char *)mod_user+mod_user_size,
+ mod->size-mod_user_size)) {
error = -EFAULT;
goto err3;
}
return simple_strtoul(cp,endp,base);
}
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long long result = 0,value;
+
+ if (!base) {
+ base = 10;
+ if (*cp == '0') {
+ base = 8;
+ cp++;
+ if ((*cp == 'x') && isxdigit(cp[1])) {
+ cp++;
+ base = 16;
+ }
+ }
+ }
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
+
+long long simple_strtoll(const char *cp,char **endp,unsigned int base)
+{
+ if(*cp=='-')
+ return -simple_strtoull(cp+1,endp,base);
+ return simple_strtoull(cp,endp,base);
+}
+
static int skip_atoi(const char **s)
{
int i=0;
if (count) {
remove_suid(inode);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
+ mark_inode_dirty_sync(inode);
}
while (count) {
if (cached_page)
page_cache_free(cached_page);
+ /* For now, when the user asks for O_SYNC, we'll actually
+ * provide O_DSYNC. */
+ if ((status >= 0) && (file->f_flags & O_SYNC))
+ status = generic_osync_inode(inode, 1); /* 1 means datasync */
+
err = written ? written : status;
out:
+
up(&inode->i_sem);
return err;
fail_write:
out_free_success:
page_cache_release(page);
return 1;
-out_failed:
- return 0;
out_unlock_restore:
set_pte(page_table, pte);
UnlockPage(page);
#endif /* CONFIG_PROC_FS */
#ifdef MODULE
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_AUTHOR("Dag Brattli <dag@brattli.net>");
MODULE_DESCRIPTION("IrCOMM protocol");
int init_module(void)
memset(&driver, 0, sizeof(struct tty_driver));
driver.magic = TTY_DRIVER_MAGIC;
driver.driver_name = "ircomm";
+#ifdef CONFIG_DEVFS_FS
+ driver.name = "ircomm%d";
+#else
driver.name = "ircomm";
+#endif
driver.major = IRCOMM_TTY_MAJOR;
driver.minor_start = IRCOMM_TTY_MINOR;
driver.num = IRCOMM_TTY_PORTS;
self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
irlan_client_get_value_confirm);
/* Get some values from peer IAS */
+ irlan_next_client_state(self, IRLAN_QUERY);
iriap_getvaluebyclass_request(self->client.iriap,
self->saddr, self->daddr,
"IrLAN", "IrDA:TinyTP:LsapSel");
-
- irlan_next_client_state(self, IRLAN_QUERY);
break;
case IRLAN_WATCHDOG_TIMEOUT:
IRDA_DEBUG(2, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
* Version: 0.9
* Description: IrLAP state machine implementation
* Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
+ * Author: Dag Brattli <dag@brattli.net>
* Created at: Sat Aug 16 00:59:29 1997
* Modified at: Sat Dec 25 21:07:57 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
+ * Modified by: Dag Brattli <dag@brattli.net>
*
* Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>,
* Copyright (c) 1998 Thomas Davis <ratbert@radiks.net>
* since we want to work even with devices that violate the
* timing requirements.
*/
- if (irda_device_is_receiving(self->netdev)) {
- IRDA_DEBUG(1, __FUNCTION__
+ if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
+ IRDA_DEBUG(2, __FUNCTION__
"(), device is slow to answer, "
"waiting some more!\n");
irlap_start_slot_timer(self, MSECS_TO_JIFFIES(10));
+ self->add_wait = TRUE;
return ret;
}
+ self->add_wait = FALSE;
if (self->s < self->S) {
irlap_send_discovery_xid_frame(self, self->S,
* of receiving a frame (page 45, IrLAP). Check that
* we only do this once for each frame.
*/
- if (irda_device_is_receiving(self->netdev) &&
- !self->add_wait)
- {
+ if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
IRDA_DEBUG(1, "FINAL_TIMER_EXPIRED when receiving a "
"frame! Waiting a little bit more!\n");
irlap_start_final_timer(self, MSECS_TO_JIFFIES(300));