Commit 9a8827cd authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.40pre1

parent 0f3ebc91
This diff is collapsed.
......@@ -29,9 +29,9 @@ By convention, the following device nodes are used (numbers indicate the device
minor numbers):
0 = /dev/fb0 First frame buffer
32 = /dev/fb1 Second frame buffer
1 = /dev/fb1 Second frame buffer
...
224 = /dev/fb7 8th frame buffer
31 = /dev/fb31 32nd frame buffer
For backwards compatibility, you may want to create the following symbolic
links:
......
......@@ -11,3 +11,43 @@ diskspace than traditional filesystems.
You can't write to a cramfs filesystem (making it compressible and
compact also makes it _very_ hard to update on-the-fly), so you have to
create the disk image with the "mkcramfs" utility in scripts/cramfs.
Usage Notes
-----------
File sizes are limited to less than 16MB.
Maximum filesystem size is a little over 256MB. (The last file on the
filesystem is allowed to extend past 256MB.) (Comments in mkcramfs.c
suggest that ROM sizes may be limited to 64MB, though that's not a
limitation in cramfs code.)
Only the low 8 bits of gid are stored. The current version of
mkcramfs simply truncates to 8 bits, which is a potential security
issue.
Hard links are not supported, but symlinks are. (See also the TODO
comment in mkcramfs.c at the nlink test.)
Cramfs directories have no `.' or `..' entries. Directories (like
every other file on cramfs) always have a link count of 1. (There's
no need to use -noleaf in `find', btw.)
No timestamps are stored in a cramfs, so these default to the epoch
(1970 GMT). Recently-accessed files may have updated timestamps, but
the update lasts only as long as the inode is cached in memory, after
which the timestamp reverts to 1970, i.e. moves backwards in time.
Currently, cramfs must be written and read with architectures of the
same endianness, and can be read only by kernels with PAGE_CACHE_SIZE
== 4096. At least the latter of these is a bug, but it hasn't been
decided what the best fix is. For the moment if you have larger pages
you can just change the #define in mkcramfs.c, so long as you don't
mind the filesystem becoming unreadable to future kernels.
Hacker Notes
------------
See fs/cramfs/README for filesystem layout and implementation notes.
This diff is collapsed.
......@@ -10,6 +10,7 @@ difficult to maintain, add yourself with a patch if desired.
Deti Fliegl <deti@fliegl.de>
ham <ham@unsuave.com>
Bradley M Keryan <keryan@andrew.cmu.edu>
Greg Kroah-Hartman <greg@kroah.com>
Paul Mackerras <paulus@cs.anu.edu.au>
David E. Nelson <dnelson@jump.net>
Vojtech Pavlik <vojtech@suse.cz>
......@@ -104,6 +105,9 @@ THANKS file in Inaky's driver):
- Thanks to Entrega for providing PCI to USB cards, hubs and
converter products for development.
- Thanks to ConnectTech for providing a WhiteHEAT usb to
serial converter, and the documentation for the device to
allow a driver to be written.
And thanks go to (hey! in no particular order :)
......
VERSION = 2
PATCHLEVEL = 3
SUBLEVEL = 39
SUBLEVEL = 40
EXTRAVERSION =
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
......
......@@ -250,6 +250,10 @@ endmenu
source drivers/char/Config.in
source drivers/usb/Config.in
source drivers/misc/Config.in
source fs/Config.in
if [ "$CONFIG_VT" = "y" ]; then
......
......@@ -28,6 +28,7 @@ CONFIG_ALPHA_GENERIC=y
# CONFIG_ALPHA_EB64P is not set
# CONFIG_ALPHA_EB66 is not set
# CONFIG_ALPHA_EB66P is not set
# CONFIG_ALPHA_EIGER is not set
# CONFIG_ALPHA_JENSEN is not set
# CONFIG_ALPHA_LX164 is not set
# CONFIG_ALPHA_MIATA is not set
......@@ -44,14 +45,14 @@ CONFIG_ALPHA_GENERIC=y
# CONFIG_ALPHA_SABLE is not set
# CONFIG_ALPHA_TAKARA is not set
CONFIG_PCI=y
CONFIG_PCI_NAMES=y
# CONFIG_SMP is not set
CONFIG_PCI_NAMES=y
CONFIG_NET=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_KCORE_ELF=y
# CONFIG_KCORE_AOUT is not set
CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
......@@ -84,6 +85,7 @@ CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_DEV_MD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_XD is not set
# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_PARIDE_PARPORT=y
# CONFIG_PARIDE is not set
# CONFIG_BLK_DEV_IDE_MODES is not set
......@@ -92,7 +94,8 @@ CONFIG_PARIDE_PARPORT=y
#
# Networking options
#
# CONFIG_PACKET is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK is not set
# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
......@@ -135,6 +138,7 @@ CONFIG_BLK_DEV_SR=y
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
......@@ -148,6 +152,7 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
......@@ -164,6 +169,7 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
# CONFIG_SCSI_SYM53C8XX is not set
......@@ -201,6 +207,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_DEPCA is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
# CONFIG_PCNET32 is not set
......@@ -211,16 +218,27 @@ CONFIG_DE4X5=y
# CONFIG_DGRS is not set
# CONFIG_EEXPRESS_PRO100 is not set
# CONFIG_NE2K_PCI is not set
# CONFIG_SIS900 is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
#
# CONFIG_ACENIC is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
#
# Wireless LAN (non-hamradio)
#
# CONFIG_NET_RADIO is not set
#
# Token ring devices
# Token Ring driver support
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
......@@ -228,13 +246,12 @@ CONFIG_DE4X5=y
#
# Wan interfaces
#
# CONFIG_HOSTESS_SV11 is not set
# CONFIG_COSA is not set
# CONFIG_SEALEVEL_4021 is not set
# CONFIG_DLCI is not set
# CONFIG_WAN_DRIVERS is not set
# CONFIG_LAPBETHER is not set
# CONFIG_X25_ASY is not set
# CONFIG_WAN is not set
#
# PCMCIA network device support
#
# CONFIG_NET_PCMCIA is not set
#
# Amateur Radio support
......@@ -263,6 +280,11 @@ CONFIG_SERIAL=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
#
# I2C support
#
# CONFIG_I2C is not set
#
# Mice
#
......@@ -271,7 +293,16 @@ CONFIG_MOUSE=y
CONFIG_PSMOUSE=y
# CONFIG_82C710_MOUSE is not set
# CONFIG_PC110_PAD is not set
#
# Joysticks
#
# CONFIG_JOYSTICK is not set
# CONFIG_QIC02_TAPE is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
......@@ -280,17 +311,31 @@ CONFIG_PSMOUSE=y
# Video For Linux
#
# CONFIG_VIDEO_DEV is not set
#
# Joystick support
#
# CONFIG_JOYSTICK is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
# CONFIG_DRM_TDFX is not set
#
# PCMCIA character device support
#
CONFIG_PCMCIA_SERIAL=y
# CONFIG_PCMCIA_SERIAL_CS is not set
#
# USB support
#
# CONFIG_USB is not set
#
# Misc devices
#
#
# Filesystems
......@@ -298,11 +343,11 @@ CONFIG_PSMOUSE=y
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_CRAMFS is not set
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
......@@ -313,6 +358,7 @@ CONFIG_DEVPTS_FS=y
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
# CONFIG_UDF_FS is not set
# CONFIG_UFS_FS is not set
#
......@@ -320,6 +366,7 @@ CONFIG_EXT2_FS=y
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
# CONFIG_NFSD is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
......@@ -329,16 +376,20 @@ CONFIG_LOCKD=y
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_OSF_PARTITION=y
# CONFIG_SMD_DISKLABEL is not set
# CONFIG_SGI_DISKLABEL is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_SGI_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
#
# Console drivers
#
CONFIG_VGA_CONSOLE=y
#
# Frame-buffer support
#
# CONFIG_FB is not set
#
......
......@@ -439,7 +439,7 @@ static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
dentry = getdev(tmp.devname, 0);
retval = PTR_ERR(dentry);
if (IS_ERR(dentry)
if (IS_ERR(dentry))
goto out;
retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname,
"ext2", flags, NULL);
......@@ -471,7 +471,6 @@ static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags)
static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags)
{
int retval;
struct procfs_args tmp;
if (copy_from_user(&tmp, args, sizeof(tmp)))
......
......@@ -251,11 +251,13 @@ pcibios_fixup_bus(struct pci_bus *bus)
/* Propogate hose info into the subordinate devices. */
struct pci_controler *hose = (struct pci_controler *) bus->sysdata;
struct pci_dev *dev;
struct list_head *ln;
bus->resource[0] = hose->io_space;
bus->resource[1] = hose->mem_space;
for (dev = bus->devices; dev; dev = dev->sibling) {
for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
struct pci_dev *dev = pci_dev_b(ln);
if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
pcibios_fixup_device_resources(dev, bus);
}
......@@ -322,6 +324,13 @@ pcibios_fixup_pbus_ranges(struct pci_bus * bus,
ranges->mem_end -= bus->resource[1]->start;
}
int __init
pcibios_enable_device(struct pci_dev *dev)
{
/* Not needed, since we enable all devices at startup. */
return 0;
}
void __init
common_init_pci(void)
{
......@@ -339,8 +348,7 @@ common_init_pci(void)
next_busno += 1;
}
pci_assign_unassigned_resources(alpha_mv.min_io_address,
alpha_mv.min_mem_address);
pci_assign_unassigned_resources();
pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
pci_set_bus_ranges();
}
......
......@@ -274,7 +274,8 @@ srm_paging_stop (void)
}
#endif
static void __init printk_memory_info(void)
static void __init
printk_memory_info(void)
{
unsigned long codesize, reservedpages, datasize, initsize, tmp;
extern int page_is_ram(unsigned long) __init;
......
......@@ -103,7 +103,11 @@ if [ "$CONFIG_VISWS" != "y" ]; then
bool 'MCA support' CONFIG_MCA
fi
bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
if [ "$CONFIG_HOTPLUG" = "y" ] ; then
source drivers/pcmcia/Config.in
fi
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
......
......@@ -53,6 +53,7 @@ CONFIG_PCI_BIOS=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_NAMES=y
# CONFIG_MCA is not set
CONFIG_HOTPLUG=y
#
# PCMCIA/CardBus support
......
......@@ -501,21 +501,14 @@ static void acpi_destroy_tables(void)
}
/*
* Locate PIIX4 device and create a fake FACP
* Init PIIX4 device and create a fake FACP
*/
static int __init acpi_find_piix4(void)
static int __init acpi_init_piix4(struct pci_dev *dev)
{
struct pci_dev *dev;
u32 base;
u16 cmd;
u8 pmregmisc;
dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_3,
NULL);
if (!dev)
return -ENODEV;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_IO))
return -ENODEV;
......@@ -567,6 +560,97 @@ static int __init acpi_find_piix4(void)
return 0;
}
/*
* Init VIA ACPI device and create a fake FACP
*/
static int __init acpi_init_via(struct pci_dev *dev)
{
u32 base;
u8 tmp, irq;
pci_read_config_byte(dev, 0x41, &tmp);
if (!(tmp & 0x80))
return -ENODEV;
pci_read_config_byte(dev, 8, &tmp);
tmp = (tmp & 0x10 ? 0x48 : 0x20);
pci_read_config_dword(dev, tmp, &base);
if (!(base & PCI_BASE_ADDRESS_SPACE_IO))
return -ENODEV;
base &= PCI_BASE_ADDRESS_IO_MASK;
if (!base)
return -ENODEV;
pci_read_config_byte(dev, 0x42, &irq);
printk(KERN_INFO "ACPI: found %s at 0x%04x\n", dev->name, base);
acpi_facp = kmalloc(sizeof(struct acpi_facp), GFP_KERNEL);
if (!acpi_facp)
return -ENOMEM;
acpi_fake_facp = 1;
memset(acpi_facp, 0, sizeof(struct acpi_facp));
acpi_facp->int_model = ACPI_VIA_INT_MODEL;
acpi_facp->sci_int = irq;
acpi_facp->smi_cmd = base + ACPI_VIA_SMI_CMD;
acpi_facp->acpi_enable = ACPI_VIA_ACPI_ENABLE;
acpi_facp->acpi_disable = ACPI_VIA_ACPI_DISABLE;
acpi_facp->pm1a_evt = base + ACPI_PIIX4_PM1_EVT;
acpi_facp->pm1a_cnt = base + ACPI_PIIX4_PM1_CNT;
acpi_facp->pm_tmr = base + ACPI_VIA_PM_TMR;
acpi_facp->gpe0 = base + ACPI_VIA_GPE0;
acpi_facp->pm1_evt_len = ACPI_VIA_PM1_EVT_LEN;
acpi_facp->pm1_cnt_len = ACPI_VIA_PM1_CNT_LEN;
acpi_facp->pm_tm_len = ACPI_VIA_PM_TM_LEN;
acpi_facp->gpe0_len = ACPI_VIA_GPE0_LEN;
acpi_facp->p_lvl2_lat = (__u16) ACPI_INFINITE_LAT;
acpi_facp->p_lvl3_lat = (__u16) ACPI_INFINITE_LAT;
acpi_facp->duty_offset = ACPI_VIA_DUTY_OFFSET;
acpi_facp->duty_width = ACPI_VIA_DUTY_WIDTH;
acpi_facp->day_alarm = ACPI_VIA_DAY_ALARM;
acpi_facp->mon_alarm = ACPI_VIA_MON_ALARM;
acpi_facp->century = ACPI_VIA_CENTURY;
acpi_facp_addr = virt_to_phys(acpi_facp);
acpi_dsdt_addr = 0;
acpi_p_blk = base + ACPI_VIA_P_BLK;
return 0;
}
static struct pci_simple_probe_entry acpi_devices[] __initdata =
{
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, 0, 0,
acpi_init_piix4},
{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, 0, 0,
acpi_init_via},
{0,}
};
/*
* Probe for matching PCI device
*/
static int __init acpi_probe(struct pci_dev *dev,
int match,
const struct pci_simple_probe_entry *entry,
void *data)
{
if(entry->dev_data) {
typedef int (*init_fn)(struct pci_dev*);
init_fn init = (init_fn) entry->dev_data;
return (*init)(dev);
}
return -ENODEV;
}
/*
* Handle an ACPI SCI (fixed or general purpose event)
*/
......@@ -692,7 +776,7 @@ static void acpi_idle_handler(void)
sleep3:
sleep_level = 3;
if (!acpi_p_lvl3_tested) {
printk("ACPI C3 works\n");
printk(KERN_INFO "ACPI C3 works\n");
acpi_p_lvl3_tested = 1;
}
wake_on_busmaster();
......@@ -732,7 +816,7 @@ static void acpi_idle_handler(void)
sleep2:
sleep_level = 2;
if (!acpi_p_lvl2_tested) {
printk("ACPI C2 works\n");
printk(KERN_INFO "ACPI C2 works\n");
acpi_p_lvl2_tested = 1;
}
wake_on_busmaster(); /* Required to track BM activity.. */
......@@ -1170,17 +1254,18 @@ static int __init acpi_init(void)
if (acpi_disabled)
return -ENODEV;
if (acpi_find_tables() && acpi_find_piix4()) {
// no ACPI tables and not PIIX4
if (acpi_find_tables()
&& pci_simple_probe(acpi_devices, 0, acpi_probe, NULL) <= 0) {
// no ACPI tables and not a recognized ACPI chipset
return -ENODEV;
}
/*
* Internally we always keep latencies in timer
* ticks, which is simpler and more consistent (what is
* an uS to us?). Besides, that gives people more
* control in the /proc interfaces.
*/
/*
* Internally we always keep latencies in timer
* ticks, which is simpler and more consistent (what is
* an uS to us?). Besides, that gives people more
* control in the /proc interfaces.
*/
if (acpi_facp->p_lvl2_lat
&& acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl2_lat);
......
......@@ -94,59 +94,56 @@
#include "pci-i386.h"
/*
* Assign new address to PCI resource. We hope our resource information
* is complete. On the PC, we don't re-assign resources unless we are
* forced to do so.
*
* Expects start=0, end=size-1, flags=resource type.
*/
int pci_assign_resource(struct pci_dev *dev, int i)
void
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
struct resource *r = &dev->resource[i];
struct resource *pr = pci_find_parent_resource(dev, r);
unsigned long size = r->end + 1;
u32 new, check;
int reg;
if (!pr) {
printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name);
return -EINVAL;
}
if (r->flags & IORESOURCE_IO) {
/*
* We need to avoid collisions with `mirrored' VGA ports and other strange
* ISA hardware, so we always want the addresses kilobyte aligned.
*/
if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large (%ld bytes)\n", dev->slot_name, i, size);
return -EFBIG;
}
if (allocate_resource(pr, r, size, 0x1000, ~0, 1024, NULL, NULL)) {
printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
return -EBUSY;
}
new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
if (resource < 6) {
reg = PCI_BASE_ADDRESS_0 + 4*resource;
} else if (resource == PCI_ROM_RESOURCE) {
res->flags |= PCI_ROM_ADDRESS_ENABLE;
reg = dev->rom_base_reg;
} else {
if (allocate_resource(pr, r, size, 0x10000000, ~0, size, NULL, NULL)) {
printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
return -EBUSY;
}
/* Bug? */
return;
}
if (i < 6) {
int reg = PCI_BASE_ADDRESS_0 + 4*i;
new = r->start | (r->flags & PCI_REGION_FLAG_MASK);
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
if (new != check)
printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check);
} else if (i == PCI_ROM_RESOURCE) {
r->flags |= PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK));
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
if (new != check) {
printk(KERN_ERR "PCI: Error while updating region "
"%s/%d (%08x != %08x)\n", dev->slot_name, resource,
new, check);
}
printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i);
return 0;
}
void
pcibios_align_resource(void *data, struct resource *res, unsigned long size)
{
struct pci_dev *dev = data;
if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start;
/* We need to avoid collisions with `mirrored' VGA ports
and other strange ISA hardware, so we always want the
addresses kilobyte aligned. */
if (size >= 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large"
" (%ld bytes)\n", dev->slot_name,
dev->resource - res, size);
}
start = (start + 1024 - 1) & ~(1024 - 1);
res->start = start;
}
}
/*
* Handle resources of PCI devices. If the world were perfect, we could
* just allocate all the resource regions and do nothing more. It isn't.
......
......@@ -23,6 +23,7 @@
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
static struct pci_bus *pci_root_bus;
static struct pci_ops *pci_root_ops;
/*
* IRQ routing table provided by the BIOS
......@@ -876,9 +877,9 @@ static void __init pci_fixup_i450nx(struct pci_dev *d)
pci_read_config_byte(d, reg++, &subb);
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
if (busno)
pci_scan_bus(busno, pci_root_bus->ops, NULL); /* Bus A */
pci_scan_bus(busno, pci_root_ops, NULL); /* Bus A */
if (suba < subb)
pci_scan_bus(suba+1, pci_root_bus->ops, NULL); /* Bus B */
pci_scan_bus(suba+1, pci_root_ops, NULL); /* Bus B */
}
}
......@@ -891,7 +892,7 @@ static void __init pci_fixup_rcc(struct pci_dev *d)
u8 busno;
pci_read_config_byte(d, 0x44, &busno);
printk("PCI: RCC host bridge: secondary bus %02x\n", busno);
pci_scan_bus(busno, pci_root_bus->ops, NULL);
pci_scan_bus(busno, pci_root_ops, NULL);
}
static void __init pci_fixup_compaq(struct pci_dev *d)
......@@ -903,7 +904,7 @@ static void __init pci_fixup_compaq(struct pci_dev *d)
u8 busno;
pci_read_config_byte(d, 0xc8, &busno);
printk("PCI: Compaq host bridge: secondary bus %02x\n", busno);
pci_scan_bus(busno, pci_root_bus->ops, NULL);
pci_scan_bus(busno, pci_root_ops, NULL);
}
static void __init pci_fixup_umc_ide(struct pci_dev *d)
......@@ -1189,7 +1190,6 @@ void __init pcibios_init(void)
{
struct pci_ops *bios = NULL;
struct pci_ops *dir = NULL;
struct pci_ops *ops;
#ifdef CONFIG_PCI_BIOS
if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) {
......@@ -1202,16 +1202,16 @@ void __init pcibios_init(void)
dir = pci_check_direct();
#endif
if (dir)
ops = dir;
pci_root_ops = dir;
else if (bios)
ops = bios;
pci_root_ops = bios;
else {
printk("PCI: No PCI bus detected\n");
return;
}
printk("PCI: Probing PCI hardware\n");
pci_root_bus = pci_scan_bus(0, ops, NULL);
pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
pcibios_fixup_irqs();
if (pci_probe & PCI_PEER_FIXUP)
......
......@@ -448,7 +448,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
struct call_data_struct data;
int ret, cpus = smp_num_cpus-1;
static spinlock_t lock = SPIN_LOCK_UNLOCKED;
unsigned long timeout;
if(cpus == 0)
return 0;
......
......@@ -138,7 +138,7 @@ static void show_registers(struct pt_regs *regs)
unsigned short ss;
unsigned long *stack, addr, module_start, module_end;
esp = (unsigned long) (1+regs);
esp = (unsigned long) (&regs->esp);
ss = __KERNEL_DS;
if (regs->xcs & 3) {
in_kernel = 0;
......
......@@ -64,6 +64,12 @@ SECTIONS
}
_end = . ;
/* Sections to be discarded */
/DISCARD/ : {
*(.text.exit)
*(.data.exit)
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
......
......@@ -22,7 +22,6 @@
*
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/signal.h>
......
......@@ -344,7 +344,7 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
static long long tty_lseek(struct file * file, long long offset, int orig)
static loff_t tty_lseek(struct file * file, loff_t offset, int orig)
{
return -ESPIPE;
}
......
......@@ -59,7 +59,7 @@ vcs_size(struct inode *inode)
return size;
}
static long long vcs_lseek(struct file *file, long long offset, int orig)
static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
{
int size = vcs_size(file->f_dentry->d_inode);
......
......@@ -12,8 +12,6 @@
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
......
......@@ -256,58 +256,6 @@ them. The MII transceiver status is polled using an kernel timer.
*/
static struct net_device *
tulip_probe1(int pci_bus, int pci_devfn, struct net_device *dev, long ioaddr,
int irq, int chip_idx, int board_idx);
/* This table drives the PCI probe routines. It's mostly boilerplate in all
of the drivers, and will likely be provided by some future kernel.
Note the matching code -- the first table entry matchs all 56** cards but
second only the 1234 card.
*/
enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
#define PCI_ADDR0_IO (PCI_USES_IO|PCI_ADDR0)
struct pci_id_info {
const char *name;
u16 vendor_id, device_id, device_id_mask, flags;
int io_size, min_latency;
struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev,
long ioaddr, int irq, int chip_idx, int fnd_cnt);
};
static struct pci_id_info pci_tbl[] = {
{ "Digital DC21040 Tulip",
0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
{ "Digital DC21041 Tulip",
0x1011, 0x0014, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
{ "Digital DS21140 Tulip",
0x1011, 0x0009, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
{ "Digital DS21143 Tulip",
0x1011, 0x0019, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
{ "Lite-On 82c168 PNIC",
0x11AD, 0x0002, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
{ "Macronix 98713 PMAC",
0x10d9, 0x0512, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
{ "Macronix 98715 PMAC",
0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
{ "Macronix 98725 PMAC",
0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
{ "ASIX AX88140",
0x125B, 0x1400, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
{ "Lite-On LC82C115 PNIC-II",
0x11AD, 0xc115, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
{ "ADMtek AN981 Comet",
0x1317, 0x0981, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
{ "Compex RL100-TX",
0x11F6, 0x9881, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
{ "Xircom Cardbus Adapter (DEC 21143 compatible mode)",
0x115D, 0x0003, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
{0},
};
/* This table use during operation for capabilities and media timer. */
static void tulip_timer(unsigned long data);
......@@ -3140,29 +3088,38 @@ static void set_rx_mode(struct net_device *dev)
outl_CSR6(csr6 | 0x0000, ioaddr, tp->chip_id);
}
static int tulip_probe(struct pci_dev *pdev)
static struct pci_device_id tulip_pci_table[] = {
{ 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 },
{ 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 },
{ 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
{ 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21142 },
{ 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
{ 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
{ 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
{ 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
{ 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
{ 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
{ 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
{ 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
{0},
};
MODULE_DEVICE_TABLE(pci, tulip_pci_table);
static int __devinit tulip_pci_probe(struct pci_dev *pdev, struct pci_device_id *id)
{
struct net_device *dev;
int chip_idx;
static int board_idx = 0;
printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name);
for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
if (pdev->vendor == pci_tbl[chip_idx].vendor_id
&& (pdev->device & pci_tbl[chip_idx].device_id_mask) ==
pci_tbl[chip_idx].device_id)
break;
if (pci_tbl[chip_idx].vendor_id == 0)
return 0;
pci_set_master(pdev);
dev = pci_tbl[chip_idx].probe1(pdev->bus->number, pdev->devfn, NULL,
dev = tulip_probe1(pdev->bus->number, pdev->devfn, NULL,
pdev->resource[0].start, pdev->irq,
chip_idx, board_idx++);
id->driver_data, board_idx++);
if (dev) {
pdev->driver_data = dev;
MOD_INC_USE_COUNT;
return 1;
}
return 0;
......@@ -3184,7 +3141,7 @@ static void tulip_resume(struct pci_dev *pdev)
if (tp->open) tulip_up(dev);
}
static void tulip_remove(struct pci_dev *pdev)
static void __devexit tulip_remove(struct pci_dev *pdev)
{
struct net_device *dev = pdev->driver_data;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
......@@ -3197,25 +3154,34 @@ static void tulip_remove(struct pci_dev *pdev)
struct pci_driver tulip_ops = {
name: "tulip_cb",
probe: tulip_probe,
id_table: tulip_pci_table,
probe: tulip_pci_probe,
remove: tulip_remove,
suspend: tulip_suspend,
resume: tulip_resume
};
int __init tulip_init(void)
#ifdef MODULE
int module_init(void)
{
pci_register_driver(&tulip_ops);
return 0;
}
void __exit tulip_cleanup(void)
void module_cleanup(void)
{
pci_unregister_driver(&tulip_ops);
}
module_init(tulip_init);
module_exit(tulip_cleanup);
#else
void tulip_probe(void)
{
pci_register_driver(&tulip_ops);
}
#endif
/*
* Local variables:
......
......@@ -24,10 +24,10 @@ ifdef CONFIG_PROC_FS
O_OBJS += proc.o
endif
L_OBJS += compat.o names.o helper.o
L_OBJS += compat.o names.o helper.o setup-res.o setup-bus.o setup-irq.o
ifndef CONFIG_X86
L_OBJS += syscall.o setup.o
L_OBJS += syscall.o
endif
include $(TOPDIR)/Rules.make
......
......@@ -202,6 +202,39 @@ pci_enable_device(struct pci_dev *dev)
static LIST_HEAD(pci_drivers);
static struct pci_device_id *
pci_match_device(struct pci_device_id *ids, struct pci_dev *dev)
{
while (ids->vendor || ids->subvendor || ids->class_mask) {
if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
(ids->device == PCI_ANY_ID || ids->device == dev->device) &&
(ids->subvendor == PCI_ANY_ID || ids->subvendor == dev->subsystem_vendor) &&
(ids->subdevice == PCI_ANY_ID || ids->subdevice == dev->subsystem_device) &&
!((ids->class ^ dev->class) & ids->class_mask))
return ids;
ids++;
}
return NULL;
}
static int
pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
{
struct pci_device_id *id;
if (drv->id_table) {
id = pci_match_device(drv->id_table, dev);
if (!id)
return 0;
} else
id = NULL;
if (drv->probe(dev, id)) {
dev->driver = drv;
return 1;
}
return 0;
}
void
pci_register_driver(struct pci_driver *drv)
{
......@@ -209,8 +242,8 @@ pci_register_driver(struct pci_driver *drv)
list_add_tail(&drv->node, &pci_drivers);
pci_for_each_dev(dev) {
if (!pci_dev_driver(dev) && drv->probe(dev))
dev->driver = drv;
if (!pci_dev_driver(dev))
pci_announce_device(drv, dev);
}
}
......@@ -229,6 +262,8 @@ pci_unregister_driver(struct pci_driver *drv)
}
}
#ifdef CONFIG_HOTPLUG
void
pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
{
......@@ -241,10 +276,8 @@ pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
#endif
for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
if (drv->probe(dev)) {
dev->driver = drv;
if (pci_announce_device(drv, dev))
break;
}
}
}
......@@ -273,6 +306,8 @@ pci_remove_device(struct pci_dev *dev)
#endif
}
#endif
static struct pci_driver pci_compat_driver = {
name: "compat"
};
......
......@@ -26,11 +26,14 @@ EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_simple_probe);
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_assign_resource);
EXPORT_SYMBOL(pci_register_driver);
EXPORT_SYMBOL(pci_unregister_driver);
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_setup_device);
EXPORT_SYMBOL(pci_insert_device);
EXPORT_SYMBOL(pci_remove_device);
EXPORT_SYMBOL(pci_register_driver);
EXPORT_SYMBOL(pci_unregister_driver);
#endif
/* Obsolete functions */
......
/*
* drivers/pci/setup.c
* drivers/pci/setup-bus.c
*
* Extruded from code written by
* Dave Rusling (david.rusling@reo.mts.dec.com)
......@@ -9,8 +9,6 @@
* Support routines for initializing a PCI subsystem.
*/
/* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
......@@ -26,129 +24,6 @@
# define DBGC(args)
#endif
int __init
pci_claim_resource(struct pci_dev *dev, int resource)
{
struct resource *res = &dev->resource[resource];
struct resource *root = pci_find_parent_resource(dev, res);
int err;
err = -EINVAL;
if (root != NULL) {
err = request_resource(root, res);
if (err) {
printk(KERN_ERR "PCI: Address space collision on "
"region %d of device %s [%lx:%lx]\n",
resource, dev->name, res->start, res->end);
}
} else {
printk(KERN_ERR "PCI: No parent found for region %d "
"of device %s\n", resource, dev->name);
}
return err;
}
static void
pdev_assign_unassigned_resources(struct pci_dev *dev, u32 min_io, u32 min_mem)
{
u32 reg;
u16 cmd;
int i;
DBGC(("PCI assign unassigned: (%s)\n", dev->name));
pci_read_config_word(dev, PCI_COMMAND, &cmd);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *root, *res;
unsigned long size, min;
res = &dev->resource[i];
if (res->flags & IORESOURCE_IO)
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;
/* Determine the root we allocate from. */
res->end -= res->start;
res->start = 0;
root = pci_find_parent_resource(dev, res);
if (root == NULL)
continue;
min = (res->flags & IORESOURCE_IO ? min_io : min_mem);
min += root->start;
size = res->end + 1;
DBGC((" for root[%lx:%lx] min[%lx] size[%lx]\n",
root->start, root->end, min, size));
if (allocate_resource(root, res, size, min, -1, size, pcibios_align_resource, dev) < 0) {
printk(KERN_ERR
"PCI: Failed to allocate resource %d for %s\n",
i, dev->name);
continue;
}
DBGC((" got res[%lx:%lx] for resource %d\n",
res->start, res->end, i));
/* Update PCI config space. */
pcibios_update_resource(dev, root, res, i);
}
/* Special case, disable the ROM. Several devices act funny
(ie. do not respond to memory space writes) when it is left
enabled. A good example are QlogicISP adapters. */
if (dev->rom_base_reg) {
pci_read_config_dword(dev, dev->rom_base_reg, &reg);
reg &= ~PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(dev, dev->rom_base_reg, reg);
dev->resource[PCI_ROM_RESOURCE].flags &= ~PCI_ROM_ADDRESS_ENABLE;
}
/* All of these (may) have I/O scattered all around and may not
use I/O base address registers at all. So we just have to
always enable IO to these devices. */
if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED
|| (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA
|| (dev->class >> 8) == PCI_CLASS_STORAGE_IDE
|| (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
cmd |= PCI_COMMAND_IO;
}
/* ??? Always turn on bus mastering. If the device doesn't support
it, the bit will go into the bucket. */
cmd |= PCI_COMMAND_MASTER;
/* 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(u32 min_io, u32 min_mem)
{
struct pci_dev *dev;
pci_for_each_dev(dev) {
pdev_assign_unassigned_resources(dev, min_io, min_mem);
}
}
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define ROUND_DOWN(x, a) ((x) & ~((a) - 1))
......@@ -279,53 +154,3 @@ pci_set_bus_ranges(void)
for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
pbus_set_ranges(pci_bus_b(ln), NULL);
}
static void __init
pdev_fixup_irq(struct pci_dev *dev,
u8 (*swizzle)(struct pci_dev *, u8 *),
int (*map_irq)(struct pci_dev *, u8, u8))
{
u8 pin, slot;
int irq;
/* If this device is not on the primary bus, we need to figure out
which interrupt pin it will come in on. We know which slot it
will come in on 'cos that slot is where the bridge is. Each
time the interrupt line passes through a PCI-PCI bridge we must
apply the swizzle function. */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
/* Cope with 0 and illegal. */
if (pin == 0 || pin > 4)
pin = 1;
/* Follow the chain of bridges, swizzling as we go. */
slot = (*swizzle)(dev, &pin);
irq = (*map_irq)(dev, slot, pin);
if (irq == -1)
irq = 0;
dev->irq = irq;
DBGC(("PCI fixup irq: (%s) got %d\n", dev->name, dev->irq));
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
pcibios_update_irq(dev, irq);
}
void __init
pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
int (*map_irq)(struct pci_dev *, u8, u8))
{
struct pci_dev *dev;
pci_for_each_dev(dev) {
pdev_fixup_irq(dev, swizzle, map_irq);
}
}
int
pcibios_enable_device(struct pci_dev *dev)
{
return 0;
}
/*
* drivers/pci/setup-irq.c
*
* Extruded from code written by
* Dave Rusling (david.rusling@reo.mts.dec.com)
* David Mosberger (davidm@cs.arizona.edu)
* David Miller (davem@redhat.com)
*
* Support routines for initializing a PCI subsystem.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
#define DEBUG_CONFIG 0
#if DEBUG_CONFIG
# define DBGC(args) printk args
#else
# define DBGC(args)
#endif
static void __init
pdev_fixup_irq(struct pci_dev *dev,
u8 (*swizzle)(struct pci_dev *, u8 *),
int (*map_irq)(struct pci_dev *, u8, u8))
{
u8 pin, slot;
int irq;
/* If this device is not on the primary bus, we need to figure out
which interrupt pin it will come in on. We know which slot it
will come in on 'cos that slot is where the bridge is. Each
time the interrupt line passes through a PCI-PCI bridge we must
apply the swizzle function. */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
/* Cope with 0 and illegal. */
if (pin == 0 || pin > 4)
pin = 1;
/* Follow the chain of bridges, swizzling as we go. */
slot = (*swizzle)(dev, &pin);
irq = (*map_irq)(dev, slot, pin);
if (irq == -1)
irq = 0;
dev->irq = irq;
DBGC(("PCI fixup irq: (%s) got %d\n", dev->name, dev->irq));
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
pcibios_update_irq(dev, irq);
}
void __init
pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
int (*map_irq)(struct pci_dev *, u8, u8))
{
struct pci_dev *dev;
pci_for_each_dev(dev) {
pdev_fixup_irq(dev, swizzle, map_irq);
}
}
/*
* drivers/pci/setup-res.c
*
* Extruded from code written by
* Dave Rusling (david.rusling@reo.mts.dec.com)
* David Mosberger (davidm@cs.arizona.edu)
* David Miller (davem@redhat.com)
*
* Support routines for initializing a PCI subsystem.
*/
/* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
#define DEBUG_CONFIG 0
#if DEBUG_CONFIG
# define DBGC(args) printk args
#else
# define DBGC(args)
#endif
int __init
pci_claim_resource(struct pci_dev *dev, int resource)
{
struct resource *res = &dev->resource[resource];
struct resource *root = pci_find_parent_resource(dev, res);
int err;
err = -EINVAL;
if (root != NULL) {
err = request_resource(root, res);
if (err) {
printk(KERN_ERR "PCI: Address space collision on "
"region %d of device %s [%lx:%lx]\n",
resource, dev->name, res->start, res->end);
}
} else {
printk(KERN_ERR "PCI: No parent found for region %d "
"of device %s\n", resource, dev->name);
}
return err;
}
int
pci_assign_resource(struct pci_dev *dev, int i)
{
struct resource *root, *res;
unsigned long size, min;
res = &dev->resource[i];
/* Determine the root we allocate from. */
res->end -= res->start;
res->start = 0;
root = pci_find_parent_resource(dev, res);
if (root == NULL) {
printk(KERN_ERR "PCI: Cannot find parent resource for "
"device %s\n", dev->slot_name);
return -EINVAL;
}
min = (res->flags & IORESOURCE_IO ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM);
min += root->start;
size = res->end + 1;
DBGC((" for root[%lx:%lx] min[%lx] size[%lx]\n",
root->start, root->end, min, size));
if (allocate_resource(root, res, size, min, -1, size,
pcibios_align_resource, dev) < 0) {
printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n",
i, dev->name);
return -EBUSY;
}
DBGC((" got res[%lx:%lx] for resource %d\n",
res->start, res->end, i));
/* Update PCI config space. */
pcibios_update_resource(dev, root, res, i);
return 0;
}
static void
pdev_assign_unassigned_resources(struct pci_dev *dev)
{
u32 reg;
u16 cmd;
int i;
DBGC(("PCI assign unassigned: (%s)\n", dev->name));
pci_read_config_word(dev, PCI_COMMAND, &cmd);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = &dev->resource[i];
if (res->flags & IORESOURCE_IO)
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
(ie. do not respond to memory space writes) when it is left
enabled. A good example are QlogicISP adapters. */
if (dev->rom_base_reg) {
pci_read_config_dword(dev, dev->rom_base_reg, &reg);
reg &= ~PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(dev, dev->rom_base_reg, reg);
dev->resource[PCI_ROM_RESOURCE].flags &= ~PCI_ROM_ADDRESS_ENABLE;
}
/* All of these (may) have I/O scattered all around and may not
use I/O base address registers at all. So we just have to
always enable IO to these devices. */
if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED
|| (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA
|| (dev->class >> 8) == PCI_CLASS_STORAGE_IDE
|| (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
cmd |= PCI_COMMAND_IO;
}
/* ??? Always turn on bus mastering. If the device doesn't support
it, the bit will go into the bucket. */
cmd |= PCI_COMMAND_MASTER;
/* 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);
}
}
......@@ -106,39 +106,12 @@ typedef struct cb_config_t {
/*=====================================================================
Expansion ROM's have a special layout, and pointers specify an
image number and an offset within that image. check_rom()
verifies that the expansion ROM exists and has the standard
layout. xlate_rom_addr() converts an image/offset address to an
absolute offset from the ROM's base address.
image number and an offset within that image. xlate_rom_addr()
converts an image/offset address to an absolute offset from the
ROM's base address.
=====================================================================*/
static int check_rom(u_char * b, u_long len)
{
u_int img = 0, ofs = 0, sz;
u_short data;
DEBUG(0, "ROM image dump:\n");
while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) {
data = readb(b + ROM_DATA_PTR) +
(readb(b + ROM_DATA_PTR + 1) << 8);
sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) +
(readb(b + data + PCDATA_IMAGE_SZ + 1) << 8));
DEBUG(0, " image %d: 0x%06x-0x%06x, signature %c%c%c%c\n",
img, ofs, ofs + sz - 1,
readb(b + data + PCDATA_SIGNATURE),
readb(b + data + PCDATA_SIGNATURE + 1),
readb(b + data + PCDATA_SIGNATURE + 2),
readb(b + data + PCDATA_SIGNATURE + 3));
ofs += sz;
img++;
if ((readb(b + data + PCDATA_INDICATOR) & 0x80) ||
(sz == 0) || (ofs >= len))
break;
b += sz;
}
return img;
}
static u_int xlate_rom_addr(u_char * b, u_int addr)
{
u_int img = 0, ofs = 0, sz;
......@@ -326,12 +299,8 @@ int cb_alloc(socket_info_t * s)
/* FIXME: Do we need to enable the expansion ROM? */
for (r = 0; r < 7; r++) {
struct resource *res = dev->resource + r;
if (res->flags) {
/* Unset resource address, assign new one! */
res->end -= res->start;
res->start = 0;
if (res->flags)
pci_assign_resource(dev, r);
}
}
pci_enable_device(dev);
......
......@@ -1129,11 +1129,11 @@ int pcmcia_get_window(window_handle_t *handle, int idx, win_req_t *req)
return CS_SUCCESS;
} /* get_window */
int pcmcia_get_first_window(client_handle_t *handle, win_req_t *req)
int pcmcia_get_first_window(window_handle_t *win, win_req_t *req)
{
if ((handle == NULL) || CHECK_HANDLE(*handle))
if ((win == NULL) || ((*win)->magic != WINDOW_MAGIC))
return CS_BAD_HANDLE;
return pcmcia_get_window((window_handle_t *)handle, 0, req);
return pcmcia_get_window(win, 0, req);
}
int pcmcia_get_next_window(window_handle_t *win, win_req_t *req)
......
......@@ -61,12 +61,10 @@
#include "i82365.h"
#include "cirrus.h"
#include "vg468.h"
#include "ricoh.h"
#include "o2micro.h"
/* PCI-bus controllers */
#include "old-yenta.h"
#include "ti113x.h"
#include "smc34c90.h"
#include "topic.h"
......
......@@ -70,9 +70,8 @@ static int pci_inquire_socket(unsigned int sock, socket_cap_t *cap)
{
pci_socket_t *socket = pci_socket_array + sock;
if (socket->op && socket->op->inquire)
return socket->op->inquire(socket, cap);
return -EINVAL;
*cap = socket->cap;
return 0;
}
static int pci_get_status(unsigned int sock, unsigned int *value)
......
......@@ -16,6 +16,9 @@ typedef struct pci_socket {
socket_cap_t cap;
wait_queue_head_t wait;
unsigned int events;
/* A few words of private data for the low-level driver.. */
unsigned int private[8];
} pci_socket_t;
struct pci_socket_ops {
......@@ -24,7 +27,6 @@ struct pci_socket_ops {
int (*init)(struct pci_socket *);
int (*suspend)(struct pci_socket *);
int (*inquire)(struct pci_socket *, socket_cap_t *cap);
int (*get_status)(struct pci_socket *, unsigned int *);
int (*get_socket)(struct pci_socket *, socket_state_t *);
int (*set_socket)(struct pci_socket *, socket_state_t *);
......
......@@ -70,25 +70,6 @@
/* Register definitions for Ricoh PCI-to-CardBus bridges */
#ifndef PCI_VENDOR_ID_RICOH
#define PCI_VENDOR_ID_RICOH 0x1180
#endif
#ifndef PCI_DEVICE_ID_RICOH_RL5C465
#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
#endif
#ifndef PCI_DEVICE_ID_RICOH_RL5C466
#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466
#endif
#ifndef PCI_DEVICE_ID_RICOH_RL5C475
#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475
#endif
#ifndef PCI_DEVICE_ID_RICOH_RL5C476
#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476
#endif
#ifndef PCI_DEVICE_ID_RICOH_RL5C478
#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478
#endif
/* Extra bits in CB_BRIDGE_CONTROL */
#define RL5C46X_BCR_3E0_ENA 0x0800
#define RL5C46X_BCR_3E2_ENA 0x1000
......@@ -129,4 +110,55 @@
#define RL5C4XX_HOLD_MASK 0x1c00
#define RL5C4XX_HOLD_SHIFT 10
#ifdef CONFIG_CARDBUS
#define rl_misc(socket) ((socket)->private[0])
#define rl_ctl(socket) ((socket)->private[1])
#define rl_io(socket) ((socket)->private[2])
#define rl_mem(socket) ((socket)->private[3])
/*
* Magic Ricoh initialization code.. Save state at
* beginning, re-initialize it after suspend.
*/
static int ricoh_open(pci_socket_t *socket)
{
rl_misc(socket) = config_readw(socket, RL5C4XX_MISC);
rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL);
rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0);
rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0);
/* Set the default timings, don't trust the original values */
rl_ctl(socket) = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
return 0;
}
static int ricoh_init(pci_socket_t *socket)
{
yenta_init(socket);
config_writew(socket, RL5C4XX_MISC, rl_misc(socket));
config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket));
config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
return 0;
}
static struct pci_socket_ops ricoh_ops = {
ricoh_open,
yenta_close,
ricoh_init,
yenta_suspend,
yenta_get_status,
yenta_get_socket,
yenta_set_socket,
yenta_get_io_map,
yenta_set_io_map,
yenta_get_mem_map,
yenta_set_mem_map,
yenta_proc_setup
};
#endif /* CONFIG_CARDBUS */
#endif /* _LINUX_RICOH_H */
......@@ -30,49 +30,6 @@
#ifndef _LINUX_TI113X_H
#define _LINUX_TI113X_H
#ifndef PCI_VENDOR_ID_TI
#define PCI_VENDOR_ID_TI 0x104c
#endif
#ifndef PCI_DEVICE_ID_TI_1130
#define PCI_DEVICE_ID_TI_1130 0xac12
#endif
#ifndef PCI_DEVICE_ID_TI_1131
#define PCI_DEVICE_ID_TI_1131 0xac15
#endif
#ifndef PCI_DEVICE_ID_TI_1031
#define PCI_DEVICE_ID_TI_1031 0xac13
#endif
#ifndef PCI_DEVICE_ID_TI_1250A
#define PCI_DEVICE_ID_TI_1250A 0xac16
#endif
#ifndef PCI_DEVICE_ID_TI_1220
#define PCI_DEVICE_ID_TI_1220 0xac17
#endif
#ifndef PCI_DEVICE_ID_TI_1221
#define PCI_DEVICE_ID_TI_1221 0xac19
#endif
#ifndef PCI_DEVICE_ID_TI_1210
#define PCI_DEVICE_ID_TI_1210 0xac1a
#endif
#ifndef PCI_DEVICE_ID_TI_1450
#define PCI_DEVICE_ID_TI_1450 0xac1b
#endif
#ifndef PCI_DEVICE_ID_TI_1225
#define PCI_DEVICE_ID_TI_1225 0xac1c
#endif
#ifndef PCI_DEVICE_ID_TI_1251A
#define PCI_DEVICE_ID_TI_1251A 0xac1d
#endif
#ifndef PCI_DEVICE_ID_TI_1211
#define PCI_DEVICE_ID_TI_1211 0xac1e
#endif
#ifndef PCI_DEVICE_ID_TI_1251B
#define PCI_DEVICE_ID_TI_1251B 0xac1f
#endif
#ifndef PCI_DEVICE_ID_TI_1420
#define PCI_DEVICE_ID_TI_1420 0xac51
#endif
/* Register definitions for TI 113X PCI-to-CardBus bridges */
......@@ -176,5 +133,86 @@
/* ExCA IO offset registers */
#define TI113X_IO_OFFSET(map) (0x36+((map)<<1))
#ifdef CONFIG_CARDBUS
#define ti_sysctl(socket) ((socket)->private[0])
#define ti_cardctl(socket) ((socket)->private[1])
#define ti_devctl(socket) ((socket)->private[2])
static int ti113x_open(pci_socket_t *socket)
{
ti_sysctl(socket) = config_readl(socket, TI113X_SYSTEM_CONTROL);
ti_cardctl(socket) = config_readb(socket, TI113X_CARD_CONTROL);
ti_devctl(socket) = config_readb(socket, TI113X_DEVICE_CONTROL);
ti_cardctl(socket) &= ~(TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC);
if (socket->cb_irq)
ti_cardctl(socket) |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC | TI113X_CCR_PCI_IREQ;
return 0;
}
static int ti113x_init(pci_socket_t *socket)
{
yenta_init(socket);
config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket));
config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket));
config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket));
return 0;
}
static struct pci_socket_ops ti113x_ops = {
ti113x_open,
yenta_close,
ti113x_init,
yenta_suspend,
yenta_get_status,
yenta_get_socket,
yenta_set_socket,
yenta_get_io_map,
yenta_set_io_map,
yenta_get_mem_map,
yenta_set_mem_map,
yenta_proc_setup
};
#define ti_diag(socket) ((socket)->private[0])
static int ti1250_open(pci_socket_t *socket)
{
ti_diag(socket) = config_readb(socket, TI1250_DIAGNOSTIC);
ti_diag(socket) &= ~(TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ);
if (socket->cb_irq)
ti_diag(socket) |= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
return 0;
}
static int ti1250_init(pci_socket_t *socket)
{
yenta_init(socket);
config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket));
return 0;
}
static struct pci_socket_ops ti1250_ops = {
ti1250_open,
yenta_close,
ti1250_init,
yenta_suspend,
yenta_get_status,
yenta_get_socket,
yenta_set_socket,
yenta_get_io_map,
yenta_set_io_map,
yenta_get_mem_map,
yenta_set_mem_map,
yenta_proc_setup
};
#endif /* CONFIG_CARDBUS */
#endif /* _LINUX_TI113X_H */
......@@ -15,7 +15,6 @@
#include "yenta.h"
#include "i82365.h"
#include "ricoh.h"
/* Don't ask.. */
#define to_cycles(ns) ((ns)/120)
......@@ -68,12 +67,6 @@ static void exca_writew(pci_socket_t *socket, unsigned reg, u16 val)
exca_writeb(socket, reg+1, val >> 8);
}
static int yenta_inquire(pci_socket_t *socket, socket_cap_t *cap)
{
*cap = socket->cap;
return 0;
}
/*
* Ugh, mixed-mode cardbus and 16-bit pccard state: things depend
* on what kind of card is inserted..
......@@ -190,13 +183,13 @@ static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state)
u16 bridge;
yenta_set_power(socket, state);
socket->io_irq = state->io_irq;
bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_CRST;
if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0;
bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN;
/* ISA interrupt control? */
if (bridge & CB_BRIDGE_INTR) {
if (!socket->cb_irq) {
u8 intr = exca_readb(socket, I365_INTCTL);
intr = (intr & ~0xf) | state->io_irq;
exca_writeb(socket, I365_INTCTL, intr);
......@@ -207,7 +200,8 @@ static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state)
reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA);
reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
reg |= state->io_irq;
if (!socket->cb_irq)
reg |= state->io_irq;
exca_writeb(socket, I365_INTCTL, reg);
reg = exca_readb(socket, I365_POWER) & (I365_VCC_MASK|I365_VPP1_MASK);
......@@ -426,7 +420,7 @@ static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* more timely manner if the state change interrupt
* works..)
*/
static int socket_thread(void * data)
static int yenta_socket_thread(void * data)
{
pci_socket_t * socket = (pci_socket_t *) data;
DECLARE_WAITQUEUE(wait, current);
......@@ -516,6 +510,7 @@ static void yenta_clear_maps(pci_socket_t *socket)
/* Called at resume and initialization events */
static int yenta_init(pci_socket_t *socket)
{
u16 bridge;
struct pci_dev *dev = socket->dev;
pci_set_power_state(socket->dev, 0);
......@@ -536,6 +531,19 @@ static int yenta_init(pci_socket_t *socket)
config_writeb(socket, PCI_SECONDARY_BUS, dev->subordinate->number);
config_writeb(socket, PCI_SUBORDINATE_BUS, dev->subordinate->number);
/*
* Set up the bridging state:
* - enable write posting.
* - memory window 0 prefetchable, window 1 non-prefetchable
* - PCI interrupts enabled if a PCI interrupt exists..
*/
bridge = config_readw(socket, CB_BRIDGE_CONTROL);
bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_INTR | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN);
bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN;
if (!socket->cb_irq)
bridge |= CB_BRIDGE_INTR;
config_writew(socket, CB_BRIDGE_CONTROL, bridge);
exca_writeb(socket, I365_GBLCTL, 0x00);
exca_writeb(socket, I365_GENCTL, 0x00);
......@@ -543,29 +551,6 @@ static int yenta_init(pci_socket_t *socket)
return 0;
}
/*
* More of an example than anything else... The standard
* yenta init code works well enough - but this is how
* you'd do it if you wanted to have a special init sequence.
*/
static int ricoh_init(pci_socket_t *socket)
{
u16 misc = config_readw(socket, RL5C4XX_MISC);
u16 ctl = config_readw(socket, RL5C4XX_16BIT_CTL);
u16 io = config_readw(socket, RL5C4XX_16BIT_IO_0);
u16 mem = config_readw(socket, RL5C4XX_16BIT_MEM_0);
ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
config_writew(socket, RL5C4XX_MISC, misc);
config_writew(socket, RL5C4XX_16BIT_CTL, ctl);
config_writew(socket, RL5C4XX_16BIT_IO_0, io);
config_writew(socket, RL5C4XX_16BIT_MEM_0, mem);
return yenta_init(socket);
}
static int yenta_suspend(pci_socket_t *socket)
{
yenta_set_socket(socket, &dead_socket);
......@@ -643,6 +628,43 @@ static void yenta_allocate_resources(pci_socket_t *socket)
yenta_allocate_res(socket, 2, IORESOURCE_IO);
}
/*
* Close it down - release our resources and go home..
*/
static void yenta_close(pci_socket_t *sock)
{
if (sock->cb_irq)
free_irq(sock->cb_irq, sock);
if (sock->base)
iounmap(sock->base);
}
#include "ti113x.h"
#include "ricoh.h"
/*
* Different cardbus controllers have slightly different
* initialization sequences etc details. List them here..
*/
#define PD(x,y) PCI_VENDOR_ID_##x, PCI_DEVICE_ID_##x##_##y
static struct cardbus_override_struct {
unsigned short vendor;
unsigned short device;
struct pci_socket_ops *op;
} cardbus_override[] = {
{ PD(TI,1130), &ti113x_ops },
{ PD(TI,1131), &ti113x_ops },
{ PD(TI,1250), &ti1250_ops },
{ PD(RICOH,RL5C465), &ricoh_ops },
{ PD(RICOH,RL5C466), &ricoh_ops },
{ PD(RICOH,RL5C475), &ricoh_ops },
{ PD(RICOH,RL5C476), &ricoh_ops },
{ PD(RICOH,RL5C478), &ricoh_ops }
};
#define NR_OVERRIDES (sizeof(cardbus_override)/sizeof(struct cardbus_override_struct))
/*
* Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the
......@@ -650,6 +672,7 @@ static void yenta_allocate_resources(pci_socket_t *socket)
*/
static int yenta_open(pci_socket_t *socket)
{
int i;
struct pci_dev *dev = socket->dev;
/*
......@@ -684,22 +707,24 @@ static int yenta_open(pci_socket_t *socket)
/* And figure out what the dang thing can do for the PCMCIA layer... */
yenta_get_socket_capabilities(socket);
kernel_thread(socket_thread, socket, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
/* Do we have special options for the device? */
for (i = 0; i < NR_OVERRIDES; i++) {
struct cardbus_override_struct *d = cardbus_override+i;
if (dev->vendor == d->vendor && dev->device == d->device) {
socket->op = d->op;
if (d->op->open) {
int retval = d->op->open(socket);
if (retval < 0)
return retval;
}
}
}
kernel_thread(yenta_socket_thread, socket, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
return 0;
}
/*
* Close it down - release our resources and go home..
*/
static void yenta_close(pci_socket_t *sock)
{
if (sock->cb_irq)
free_irq(sock->cb_irq, sock);
if (sock->base)
iounmap(sock->base);
}
/*
* Standard plain cardbus - no frills, no extensions
*/
......@@ -708,7 +733,6 @@ struct pci_socket_ops yenta_operations = {
yenta_close,
yenta_init,
yenta_suspend,
yenta_inquire,
yenta_get_status,
yenta_get_socket,
yenta_set_socket,
......@@ -728,7 +752,6 @@ struct pci_socket_ops ricoh_operations = {
yenta_close,
ricoh_init,
yenta_suspend,
yenta_inquire,
yenta_get_status,
yenta_get_socket,
yenta_set_socket,
......
......@@ -16,6 +16,8 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/isapnp.h>
#include <linux/string.h>
static void __init quirk_awe32_resources(struct pci_dev *dev)
{
......
......@@ -21,7 +21,7 @@ comment 'USB Devices'
dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB
dep_tristate ' USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
dep_tristate ' USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
......
/*
* acm.c Version 0.12
* acm.c Version 0.13
*
* Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
......@@ -496,11 +496,14 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
if (acm_table[minor]) {
dbg("no more free acm devices");
err("no more free acm devices");
return NULL;
}
if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) return NULL;
if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
err("out of memory");
return NULL;
}
memset(acm, 0, sizeof(struct acm));
ctrlsize = epctrl->wMaxPacketSize;
......@@ -512,6 +515,7 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
acm->dev = dev;
if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
err("out of memory");
kfree(acm);
return NULL;
}
......@@ -523,15 +527,15 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
buf += ctrlsize, readsize, acm_read_bulk, acm);
FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
buf += readsize , acm->writesize, acm_write_bulk, acm);
buf += readsize, acm->writesize, acm_write_bulk, acm);
printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
acm_set_control(acm, acm->ctrlout);
acm->linecoding.speed = 115200;
acm->linecoding.databits = 8;
acm_set_coding(acm, &acm->linecoding);
acm->line.speed = cpu_to_le32(9600);
acm->line.databits = 8;
acm_set_line(acm, &acm->line);
usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
......
This diff is collapsed.
......@@ -653,8 +653,6 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
{
urb_t *urb;
DECLARE_WAITQUEUE(wait, current);
DECLARE_WAIT_QUEUE_HEAD(wqh);
api_wrapper_data *awd;
if (!(urb=usb_alloc_urb(0)))
......
......@@ -111,7 +111,6 @@ struct usbdevfs_urb {
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/list.h>
#include <asm/semaphore.h>
......
This diff is collapsed.
Notes on Filesystem Layout
--------------------------
These notes describe what mkcramfs generates. Kernel requirements are
a bit looser, e.g. it doesn't care if the <file_data> items are
swapped around (though it does care that directory entries (inodes) in
a given directory are contiguous, as this is used by readdir).
All data is in host-endian format; neither mkcramfs nor the kernel
ever do swabbing. (See section `Block Size' below.)
<filesystem>:
<superblock>
<directory_structure>
<data>
<superblock>: struct cramfs_super (see cramfs.h).
<directory_structure>:
For each file:
struct cramfs_inode (see cramfs.h).
Filename. Not generally null-terminated, but it is
null-padded to a multiple of 4 bytes.
The order of inode traversal is described as "width-first" (not to be
confused with breadth-first); i.e. like depth-first but listing all of
a directory's entries before recursing down its subdirectories: the
same order as `ls -AUR' (but without the /^\..*:$/ directory header
lines); put another way, the same order as `find -type d -exec
ls -AU1 {} \;'.
<data>:
One <file_data> for each file that's either a symlink or a
regular file of non-zero st_size.
<file_data>:
nblocks * <block_pointer>
(where nblocks = (st_size - 1) / blksize + 1)
nblocks * <block>
padding to multiple of 4 bytes
The i'th <block_pointer> for a file stores the byte offset of the
*end* of the i'th <block> (i.e. one past the last byte, which is the
same as the start of the (i+1)'th <block> if there is one). The first
<block> immediately follows the last <block_pointer> for the file.
<block_pointer>s are each 32 bits long.
The order of <file_data>'s is a depth-first descent of the directory
tree, i.e. the same order as `find -size +0 \( -type f -o -type l \)
-print'.
<block>: The i'th <block> is the output of zlib's compress function
applied to the i'th blksize-sized chunk of the input data.
(For the last <block> of the file, the input may of course be smaller.)
Each <block> may be a different size. (See <block_pointer> above.)
<block>s are merely byte-aligned, not generally u32-aligned.
Holes
-----
This kernel supports cramfs holes (i.e. [efficient representation of]
blocks in uncompressed data consisting entirely of NUL bytes), but by
default mkcramfs doesn't test for & create holes, since cramfs in
kernels up to at least 2.3.39 didn't support holes. Compile mkcramfs
with -DDO_HOLES if you want it to create files that can have holes in
them.
Tools
-----
If you're hacking on cramfs, you might find useful some tools for
testing cramfs at <http://cvs.bofh.asn.au/cramfs/>, including a
rudimentary fsck for cramfs.
Future Development
==================
Block Size
----------
(Block size in cramfs refers to the size of input data that is
compressed at a time. It's intended to be somewhere around
PAGE_CACHE_SIZE for cramfs_readpage's convenience.)
The superblock ought to indicate the block size that the fs was
written for, since comments in <linux/pagemap.h> indicate that
PAGE_CACHE_SIZE may grow in future (if I interpret the comment
correctly).
Currently, mkcramfs #define's PAGE_CACHE_SIZE as 4096 and uses that
for blksize, whereas Linux-2.3.39 uses its PAGE_CACHE_SIZE, which in
turn is defined as PAGE_SIZE (which can be as large as 32KB on arm).
This discrepancy is a bug, though it's not clear which should be
changed.
One option is to change mkcramfs to take its PAGE_CACHE_SIZE from
<asm/page.h>. Personally I don't like this option, but it does
require the least amount of change: just change `#define
PAGE_CACHE_SIZE (4096)' to `#include <asm/page.h>'. The disadvantage
is that the generated cramfs cannot always be shared between different
kernels, not even necessarily kernels of the same architecture if
PAGE_CACHE_SIZE is subject to change between kernel versions.
The remaining options try to make cramfs more sharable.
One part of that is addressing endianness. The two options here are
`always use little-endian' (like ext2fs) or `writer chooses
endianness; kernel adapts at runtime'. Little-endian wins because of
code simplicity and little CPU overhead even on big-endian machines.
The cost of swabbing is changing the code to use the le32_to_cpu
etc. macros as used by ext2fs. We don't need to swab the compressed
data, only the superblock, inodes and block pointers.
The other part of making cramfs more sharable is choosing a block
size. The options are:
1. Always 4096 bytes.
2. Writer chooses blocksize; kernel adapts but rejects blocksize >
PAGE_CACHE_SIZE.
3. Writer chooses blocksize; kernel adapts even to blocksize >
PAGE_CACHE_SIZE.
It's easy enough to change the kernel to use a smaller value than
PAGE_CACHE_SIZE: just make cramfs_readpage read multiple blocks.
The cost of option 1 is that kernels with a larger PAGE_CACHE_SIZE
value don't get as good compression as they can.
The cost of option 2 relative to option 1 is that the code uses
variables instead of #define'd constants. The gain is that people
with kernels having larger PAGE_CACHE_SIZE can make use of that if
they don't mind their cramfs being inaccessible to kernels with
smaller PAGE_CACHE_SIZE values.
Option 3 is easy to implement if we don't mind being CPU-inefficient:
e.g. get readpage to decompress to a buffer of size MAX_BLKSIZE (which
must be no larger than 32KB) and discard what it doesn't need.
Getting readpage to read into all the covered pages is harder.
The main advantage of option 3 over 1, 2, is better compression. The
cost is greater complexity. Probably not worth it, but I hope someone
will disagree. (If it is implemented, then I'll re-use that code in
e2compr.)
Another cost of 2 and 3 over 1 is making mkcramfs use a different
block size, but that just means adding and parsing a -b option.
Inode Size
----------
Given that cramfs will probably be used for CDs etc. as well as just
silicon ROMs, it might make sense to expand the inode a little from
its current 12 bytes. Inodes other than the root inode are followed
by filename, so the expansion doesn't even have to be a multiple of 4
bytes.
......@@ -5,17 +5,20 @@
#define CRAMFS_SIGNATURE "Compressed ROMFS"
/*
* Reasonably terse representation of the inode
* data.. When the mode of the inode indicates
* a special device node, the "offset" bits will
* encode i_rdev. In other cases, "offset" points
* to the ROM image for the actual file data
* (whether that data be directory or compressed
* file data depends on the inode type again)
* Reasonably terse representation of the inode data.
*/
struct cramfs_inode {
u32 mode:16, uid:16;
/* SIZE for device files is i_rdev */
u32 size:24, gid:8;
/* NAMELEN is the length of the file name, divided by 4 and
rounded up. (cramfs doesn't support hard links.) */
/* OFFSET: For symlinks and non-empty regular files, this
contains the offset (divided by 4) of the file data in
compressed form (starting with an array of block pointers;
see README). For non-empty directories it is the offset
(divided by 4) of the inode of the first file in that
directory. For anything else, offset is zero. */
u32 namelen:6, offset:26;
};
......@@ -24,7 +27,8 @@ struct cramfs_inode {
*/
struct cramfs_super {
u32 magic; /* 0x28cd3d45 - random number */
u32 size; /* > offset, < 2**26 */
u32 size; /* Not used. mkcramfs currently
writes a constant 1<<16 here. */
u32 flags; /* 0 */
u32 future; /* 0 */
u8 signature[16]; /* "Compressed ROMFS" */
......@@ -33,6 +37,13 @@ struct cramfs_super {
struct cramfs_inode root; /* Root inode data */
};
/*
* Valid values in super.flags. Currently we refuse to mount
* if (flags & ~CRAMFS_SUPPORTED_FLAGS). Maybe that should be
* changed to test super.future instead.
*/
#define CRAMFS_SUPPORTED_FLAGS (0xff)
/* Uncompression interfaces to the underlying zlib */
int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen);
int cramfs_uncompress_init(void);
......
......@@ -27,7 +27,10 @@ static struct inode_operations cramfs_file_inode_operations;
static struct inode_operations cramfs_dir_inode_operations;
static struct inode_operations cramfs_symlink_inode_operations;
/* These two macros may change in future, to provide better st_ino
semantics. */
#define CRAMINO(x) ((x)->offset?(x)->offset<<2:1)
#define OFFSET(x) ((x)->i_ino)
static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode)
{
......@@ -41,6 +44,12 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
inode->i_ino = CRAMINO(cramfs_inode);
inode->i_sb = sb;
inode->i_dev = sb->s_dev;
inode->i_nlink = 1; /* arguably wrong for directories,
but it's the best we can do
without reading the directory
contents. 1 yields the right
result in GNU find, even
without -noleaf option. */
insert_inode_hash(inode);
if (S_ISREG(inode->i_mode))
inode->i_op = &cramfs_file_inode_operations;
......@@ -62,45 +71,75 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
* up the accesses should be fairly regular and cached in the
* page cache and dentry tree anyway..
*
* This also acts as a way to guarantee contiguous areas of
* up to 2*PAGE_CACHE_SIZE, so that the caller doesn't need
* to worry about end-of-buffer issues even when decompressing
* a full page cache.
* This also acts as a way to guarantee contiguous areas of up to
* BLKS_PER_BUF*PAGE_CACHE_SIZE, so that the caller doesn't need to
* worry about end-of-buffer issues even when decompressing a full
* page cache.
*/
#define READ_BUFFERS (2)
static unsigned char read_buffers[READ_BUFFERS][PAGE_CACHE_SIZE*4];
static int buffer_blocknr[READ_BUFFERS];
static int last_buffer = 0;
/* NEXT_BUFFER(): Loop over [0..(READ_BUFFERS-1)]. */
#define NEXT_BUFFER(_ix) ((_ix) ^ 1)
static void *cramfs_read(struct super_block *sb, unsigned int offset)
/*
* BLKS_PER_BUF_SHIFT must be at least 1 to allow for "compressed"
* data that takes up more space than the original. 1 is guaranteed
* to suffice, though. Larger values provide more read-ahead and
* proportionally less wastage at the end of the buffer.
*/
#define BLKS_PER_BUF_SHIFT (2)
#define BLKS_PER_BUF (1 << BLKS_PER_BUF_SHIFT)
static unsigned char read_buffers[READ_BUFFERS][BLKS_PER_BUF][PAGE_CACHE_SIZE];
static unsigned buffer_blocknr[READ_BUFFERS];
static int next_buffer = 0;
/*
* Returns a pointer to a buffer containing at least LEN bytes of
* filesystem starting at byte offset OFFSET into the filesystem.
*/
static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
{
struct buffer_head * bh_array[4];
int i, blocknr, buffer;
struct buffer_head * bh_array[BLKS_PER_BUF];
unsigned i, blocknr, last_blocknr, buffer;
if (!len)
return NULL;
blocknr = offset >> PAGE_CACHE_SHIFT;
offset &= PAGE_CACHE_SIZE-1;
last_blocknr = (offset + len - 1) >> PAGE_CACHE_SHIFT;
if (last_blocknr - blocknr >= BLKS_PER_BUF)
goto eek; resume:
offset &= PAGE_CACHE_SIZE - 1;
for (i = 0; i < READ_BUFFERS; i++) {
if (blocknr == buffer_blocknr[i])
return read_buffers[i] + offset;
if ((blocknr >= buffer_blocknr[i]) &&
(last_blocknr - buffer_blocknr[i] < BLKS_PER_BUF))
return &read_buffers[i][blocknr - buffer_blocknr[i]][offset];
}
/* Ok, read in four buffers completely first */
for (i = 0; i < 4; i++)
/* Ok, read in BLKS_PER_BUF pages completely first. */
for (i = 0; i < BLKS_PER_BUF; i++)
bh_array[i] = bread(sb->s_dev, blocknr + i, PAGE_CACHE_SIZE);
/* Ok, copy them to the staging area without sleeping.. */
buffer = last_buffer;
last_buffer = buffer ^ 1;
/* Ok, copy them to the staging area without sleeping. */
buffer = next_buffer;
next_buffer = NEXT_BUFFER(buffer);
buffer_blocknr[buffer] = blocknr;
for (i = 0; i < 4; i++) {
for (i = 0; i < BLKS_PER_BUF; i++) {
struct buffer_head * bh = bh_array[i];
if (bh) {
memcpy(read_buffers[buffer] + i*PAGE_CACHE_SIZE, bh->b_data, PAGE_CACHE_SIZE);
memcpy(read_buffers[buffer][i], bh->b_data, PAGE_CACHE_SIZE);
bforget(bh);
}
blocknr++;
} else
memset(read_buffers[buffer][i], 0, PAGE_CACHE_SIZE);
}
return read_buffers[buffer] + offset;
return read_buffers[buffer][0] + offset;
eek:
printk(KERN_ERR
"cramfs (device %s): requested chunk (%u:+%u) bigger than buffer\n",
bdevname(sb->s_dev), offset, len);
/* TODO: return EIO to process or kill the current process
instead of resuming. */
*((int *)0) = 0; /* XXX: doesn't work on all archs */
goto resume;
}
......@@ -121,7 +160,7 @@ static struct super_block * cramfs_read_super(struct super_block *sb, void *data
buffer_blocknr[i] = -1;
/* Read the first block and get the superblock from it */
memcpy(&super, cramfs_read(sb, 0), sizeof(super));
memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
/* Do sanity checks on the superblock */
if (super.magic != CRAMFS_MAGIC) {
......@@ -132,21 +171,23 @@ static struct super_block * cramfs_read_super(struct super_block *sb, void *data
printk("wrong signature\n");
goto out;
}
/* Check that the root inode is in a sane state */
root_offset = super.root.offset << 2;
if (root_offset < sizeof(struct cramfs_super)) {
printk("root offset too small\n");
goto out;
}
if (root_offset >= super.size) {
printk("root offset too large (%lu %u)\n", root_offset, super.size);
if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
printk("unsupported filesystem features\n");
goto out;
}
/* Check that the root inode is in a sane state */
if (!S_ISDIR(super.root.mode)) {
printk("root is not a directory\n");
goto out;
}
root_offset = super.root.offset << 2;
if (root_offset == 0)
printk(KERN_INFO "cramfs: note: empty filesystem");
else if (root_offset != sizeof(struct cramfs_super)) {
printk("bad root offset %lu\n", root_offset);
goto out;
}
/* Set it all up.. */
sb->s_op = &cramfs_ops;
......@@ -168,19 +209,20 @@ static int cramfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize
{
struct statfs tmp;
memset(&tmp, 0, sizeof(tmp));
/* Unsupported fields set to -1 as per man page. */
memset(&tmp, 0xff, sizeof(tmp));
tmp.f_type = CRAMFS_MAGIC;
tmp.f_bsize = PAGE_CACHE_SIZE;
tmp.f_blocks = 0;
tmp.f_bfree = 0;
tmp.f_bavail = 0;
tmp.f_ffree = 0;
tmp.f_namelen = 255;
return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
}
/*
* Read a cramfs directory entry..
*
* Remember: the inode number is the byte offset of the start
* of the directory..
* Read a cramfs directory entry.
*/
static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
......@@ -189,7 +231,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
unsigned int offset;
int copied;
/* Offset within the thing.. */
/* Offset within the thing. */
offset = filp->f_pos;
if (offset >= inode->i_size)
return 0;
......@@ -204,7 +246,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
char *name;
int namelen, error;
de = cramfs_read(sb, offset + inode->i_ino);
de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+256);
name = (char *)(de+1);
/*
......@@ -244,7 +286,7 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry)
char *name;
int namelen;
de = cramfs_read(dir->i_sb, offset + dir->i_ino);
de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+256);
name = (char *)(de+1);
namelen = de->namelen << 2;
offset += sizeof(*de) + namelen;
......@@ -274,27 +316,29 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry)
static int cramfs_readpage(struct dentry *dentry, struct page * page)
{
struct inode *inode = dentry->d_inode;
unsigned long maxblock, bytes;
u32 maxblock, bytes_filled;
maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
bytes = 0;
bytes_filled = 0;
if (page->index < maxblock) {
struct super_block *sb = inode->i_sb;
unsigned long block_offset = inode->i_ino + page->index*4;
unsigned long start_offset = inode->i_ino + maxblock*4;
unsigned long end_offset;
u32 blkptr_offset = OFFSET(inode) + page->index*4;
u32 start_offset, compr_len;
end_offset = *(u32 *) cramfs_read(sb, block_offset);
start_offset = OFFSET(inode) + maxblock*4;
if (page->index)
start_offset = *(u32 *) cramfs_read(sb, block_offset-4);
bytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
if (page->index < maxblock)
bytes = PAGE_CACHE_SIZE;
cramfs_uncompress_block((void *) page_address(page), PAGE_CACHE_SIZE, cramfs_read(sb, start_offset), end_offset - start_offset);
start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4)
- start_offset);
if (compr_len == 0)
; /* hole */
else
bytes_filled = cramfs_uncompress_block((void *) page_address(page),
PAGE_CACHE_SIZE,
cramfs_read(sb, start_offset, compr_len),
compr_len);
}
memset((void *) (page_address(page) + bytes), 0, PAGE_CACHE_SIZE - bytes);
memset((void *) (page_address(page) + bytes_filled), 0, PAGE_CACHE_SIZE - bytes_filled);
SetPageUptodate(page);
UnlockPage(page);
return 0;
......
This diff is collapsed.
......@@ -28,7 +28,7 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
static long long ext2_file_lseek(struct file *, long long, int);
static loff_t ext2_file_lseek(struct file *, loff_t, int);
static int ext2_open_file (struct inode *, struct file *);
#define EXT2_MAX_SIZE(bits) \
......@@ -45,9 +45,9 @@ EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13)
/*
* Make sure the offset never goes beyond the 32-bit mark..
*/
static long long ext2_file_lseek(
static loff_t ext2_file_lseek(
struct file *file,
long long offset,
loff_t offset,
int origin)
{
struct inode *inode = file->f_dentry->d_inode;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment