N: Matt Welsh
E: mdw@sunsite.unc.edu
D: Linux Documentation Project coordinator
-D: Author, Linux Installation and Getting Started
-D: HOWTO coordinator and writer
-D: Maintainer of sunsite.unc.edu Linux doc archives
-D: Moderator, comp.os.linux.announce
-S: 205 Gray Street NE
-S: Wilson, North Carolina 27893
+D: Author, _Running_Linux_ and I&GS guide
+D: Linuxdoc-SGML formatting system
+D: Keithley DAS1200 device driver
+D: Maintainer of sunsite WWW and FTP, moderator c.o.l.answers
+S: Cornell University Computer Science Department
+S: Robotics and Vision Laboratory
+S: 4130 Upson Hall
+S: Ithaca NY 14850
S: USA
N: Marco van Wieringen
VERSION = 1
PATCHLEVEL = 3
-SUBLEVEL = 20
+SUBLEVEL = 21
ARCH = i386
# Rule to compile a set of .o files into one .o file
#
ifdef O_TARGET
-$(O_TARGET): $(O_OBJS)
+$(O_TARGET): $(O_OBJS) $(TOPDIR)/include/linux/config.h
+ rm -f $@
ifdef O_OBJS
$(LD) $(EXTRA_LDFLAGS) -r -o $@ $(O_OBJS)
else
# Rule to compile a set of .o files into one .a file
#
ifdef L_TARGET
-$(L_TARGET): $(L_OBJS)
+$(L_TARGET): $(L_OBJS) $(TOPDIR)/include/linux/config.h
rm -f $@
$(AR) $(EXTRA_ARFLAGS) rcs $@ $(L_OBJS)
endif
bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
bool 'PCI bios support' CONFIG_PCI y
if [ "$CONFIG_PCI" = "y" ]; then
- bool ' PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE y
+ bool ' PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE y
+ if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
+ bool ' PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON y
+ fi
fi
bool 'System V IPC' CONFIG_SYSVIPC y
bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y
.long SYMBOL_NAME(sys_getdents)
.long SYMBOL_NAME(sys_select)
.long SYMBOL_NAME(sys_flock)
- .space (NR_syscalls-143)*4
+ .long SYMBOL_NAME(sys_msync)
+ .space (NR_syscalls-144)*4
init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
for (;;) {
+ /*
+ * "mem=nopentium" disables the 4MB page tables.
+ * "mem=XXX[kKmM]" overrides the BIOS-reported
+ * memory size
+ */
if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
- memory_end = simple_strtoul(from+4, &from, 0);
- if ( *from == 'K' || *from == 'k' ) {
- memory_end = memory_end << 10;
- from++;
- } else if ( *from == 'M' || *from == 'm' ) {
- memory_end = memory_end << 20;
- from++;
+ if (!memcmp(from+4, "nopentium", 9)) {
+ from += 9+4;
+ x86_capability &= ~8;
+ } else {
+ memory_end = simple_strtoul(from+4, &from, 0);
+ if ( *from == 'K' || *from == 'k' ) {
+ memory_end = memory_end << 10;
+ from++;
+ } else if ( *from == 'M' || *from == 'm' ) {
+ memory_end = memory_end << 20;
+ from++;
+ }
}
}
c = *(from++);
L_OBJS += ide.o
endif
+ifdef CONFIG_BLK_DEV_TRITON
+L_OBJS += triton.o
+endif
+
ifdef CONFIG_BLK_DEV_IDECD
L_OBJS += ide-cd.o
endif
Supported by: mlord@bnr.ca -- disks, interfaces, probing
snyder@fnald0.fnal.gov -- cdroms, ATAPI, audio
-(see description later on below for handling BIG IDE drives with >1024 cyls).
+ +-----------------------------------------------------------------+
+ | The hdparm utility for controlling various IDE features is |
+ | packaged separately. Look for it on popular linux FTP sites. |
+ +-----------------------------------------------------------------+
+
+See description later on below for handling BIG IDE drives with >1024 cyls.
Major features of ide.c & ide-cd.c:
NEW! - should work for for EZ-Drive disks as well (not verified)
- works with Linux fdisk, LILO, loadlin, bootln, etc..
NEW! - ide-cd.c now compiles separate from ide.c
+NEW! - Bus-Master DMA support for Intel PCI Triton chipset IDE interfaces
+ - for details, see comments at top of triton.c
-For a list of work underway, see the comments near the top of ide.c and ide-cd.c
+For work in progress, see the comments in ide.c, ide-cd.c, and triton.c.
***
-
-IMPORTANT NOTICE: "CMD" EIDE Interfaces will not (by default) work *reliably*
-when drives are attached to the second interface. To "fix" this, supply the
-special kernel "command line" parameter to LILO: ide1=serialize
-Failure to do so can cause severe data corruption!
-
+*** IMPORTANT NOTICES:
+*** ==================
+***
+*** "CMD" EIDE Interfaces will not (by default) work *reliably* when drives
+*** are attached to the second interface. This is due to a flaw in the
+*** hardware. To "fix" this, supply the special kernel "command line"
+*** parameter to LILO or LOADLIN: ide1=serialize
+***
+*** "CMD 640B" EIDE Interfaces will not work *reliably* when "hdparm -u1"
+*** (interrupt unmasking) is used. This is due to a flaw in the hardware,
+*** and is only a problem when "hdparm -u1" is used after booting.
+***
+*** "RZ1000" EIDE Interfaces will also not work *reliably* when "hdparm -u1"
+*** (interrupt unmasking) is used. This is due to a flaw in the hardware,
+*** and is only a problem when "hdparm -u1" is used after booting.
+***
+*** Failure to abide by these restrictions can cause severe data corruption!
***
To access devices on the 2nd/3rd/4th interfaces, device entries must first be
Drives are normally found by auto-probing and/or examining the CMOS/BIOS data.
For really weird situations, the apparent (fdisk) geometry can also be specified
-on the kernel "command line" using LILO. The format of such lines is:
+on the kernel "command line" using LILO. The format of such lines is:
hdx=cyls,heads,sects,wpcom,irq
or hdx=cdrom
under control of ide.c. To have ide.c also "take over" the primary
IDE port in this situation, use the "command line" parameter: ide0=0x1f0
-The hdparm.c program for controlling various IDE features is now packaged
-separately. Look for it on popular linux FTP sites.
-
mlord@bnr.ca
snyder@fnald0.fnal.gov
================================================================================
"hdx=" is recognized for all "x" from "a" to "h", such as "hdc".
"idex=" is recognized for all "x" from "0" to "3", such as "ide1".
-
+
"hdx=noprobe" : drive may be present, but do not probe for it
"hdx=nowerr" : ignore the WRERR_STAT bit on this drive
"hdx=cdrom" : drive is present, and is a cdrom drive
0. Boot from the "boot floppy" created during the installation
1. Mount your DOS partition as /dos (and stick it in /etc/fstab)
2. Move your kernel (/vmlinuz) to /dos/vmlinuz with: mv /vmlinuz /dos
- 3. Edit /etc/lilo.conf to change /vmlinuz to /dos/vmlinuz
+ 3. Edit /etc/lilo.conf to change /vmlinuz to /dos/vmlinuz
4. Move /boot to /dos/boot with: cp -a /boot /dos ; rm -r /boot
5. Create a symlink for LILO to use with: ln -s /dos/boot /boot
6. Re-run LILO with: lilo
This is the README file for the Optics Storage 8000 AT CDROM device driver.
-The driver contains code to enable an ISP16 interface if it finds one, so if
-you have that, you're lucky.
-
-My configuration code for the ISP-16 card can get found at
+The driver contains code to enable an ISP16 interface if it finds one. It
+didn't originally (although this README erroneously said so), because I think
+this kind of code should go into its own module. But having to use a hack all
+the time in order to use a part of the standard kernel started to annoy me, so
+I copied the ISP16 code by Eric van der Maarel (maarel@marin.nl) from Vadim
+Model's Sanyo sjcd driver. I'll remove it again from this driver when we have
+some common way to talk to ISP16 interfaces.
+
+My original configuration code for the ISP-16 card can get found at
dutette.et.tudelft.nl:/pub/linux/
and at Eberhard's mirror
ftp.gwdg.de:/pub/linux/cdrom/drivers/optics/
with the matching address value of your interface card.
I have tried the module with several 1.2.x kernel versions, and it seems to
-work, as far as I tested. If you use it, I'd appreciate success/failure
-reports.
+work, as far as I tested. It also seems to work for several 1.3.x versions.
+If you use it, I'd appreciate success/failure reports. If you find a bug,
+try recompiling the driver with some strategically chosen #undef DEBUG_...'s
+changed into #defines (you'll find them in .../include/linux/optcd.h) and
+include the messages generated in your bug report. Good luck.
Leo Spiekman (spiekman@dutette.et.tudelft.nl)
#if ! SCSI_MAJOR(MAJOR_NR)
-#ifdef _IDE_CD_C /* ide-cd.c uses copy from ide.c */
+#if defined(_IDE_CD_C) || defined(_TRITON_C) /* shares copy with ide.c */
void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
#else
#define PACKET_COMMAND 4315
#define REQUEST_SENSE_COMMAND 4316
-#define WIN_PACKETCMD 0xa0 /* Send a packet command. */
-
/* Some ATAPI command opcodes (just like SCSI).
(Some other cdrom-specific codes are in cdrom.h.) */
#define TEST_UNIT_READY 0x00
/*
- * linux/drivers/block/ide.c Version 5.03 Aug 13, 1995
+ * linux/drivers/block/ide.c Version 5.10 Aug 26, 1995
*
* Copyright (C) 1994, 1995 Linus Torvalds & authors (see below)
*/
* Version 5.03 tune-ups, comments, remove "busy wait" from drive resets
* removed PROBE_FOR_IRQS option -- no longer needed
* OOOPS! fixed "bad access" bug for 2nd drive on an i/f
+ * Version 5.04 changed "ira %d" to "irq %d" in DEBUG message
+ * added more comments, cleaned up unexpected_intr()
+ * OOOPS! fixed null pointer problem in ide reset code
+ * added autodetect for Triton chipset -- no effect yet
+ * Version 5.05 OOOPS! fixed bug in revalidate_disk()
+ * OOOPS! fixed bug in ide_do_request()
+ * added ATAPI reset sequence for cdroms
+ * Version 5.10 added Bus-Mastered DMA support for Triton Chipset
+ * some (mostly) cosmetic changes
*
* Driver compile-time options are in ide.h
*
* To do, in likely order of completion:
* - add in several updates from my email collection (soon folks!)
- * - add full support for Intel Triton chipset, including bus-mastered DMA
* - improved CMD support: handing this off to someone else
* - find someone to work on IDE *tape drive* support
*/
#include <asm/byteorder.h>
#include <asm/irq.h>
+#ifdef CONFIG_PCI
+#include <linux/bios32.h>
+#endif /* CONFIG_PCI */
+
#include "ide.h"
static ide_hwif_t ide_hwifs[MAX_HWIFS]; /* hwif info */
* ide_drive_t structs as needed, rather than always consuming memory
* for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
*/
+#define MAGIC_COOKIE 0x12345678
static void init_ide_data (void)
{
+ byte *p;
unsigned int h, unit;
- static unsigned long magic_cookie = 0x12345678;
+ static unsigned long magic_cookie = MAGIC_COOKIE;
- if (magic_cookie != 0x12345678)
+ if (magic_cookie != MAGIC_COOKIE)
return; /* already initialized */
magic_cookie = 0;
for (h = 0; h < 16; ++h)
irq_to_hwgroup[h] = NULL;
+ /* bulk initialize hwif & drive info with zeros */
+ p = ((byte *) ide_hwifs) + sizeof(ide_hwifs);
+ do {
+ *--p = 0;
+ } while (p > (byte *) ide_hwifs);
+
for (h = 0; h < MAX_HWIFS; ++h) {
ide_hwif_t *hwif = &ide_hwifs[h];
+ /* fill in any non-zero initial values */
hwif->noprobe = (h > 1);
- hwif->hwgroup = NULL;
hwif->io_base = default_io_base[h];
hwif->ctl_port = hwif->io_base ? hwif->io_base + 0x206 : 0x000;
#ifdef CONFIG_BLK_DEV_HD
if (hwif->io_base == HD_DATA)
hwif->noprobe = 1; /* may be overriden by ide_setup() */
#endif /* CONFIG_BLK_DEV_HD */
- hwif->gd = NULL;
- hwif->irq = 0; /* default_irqs[h] used when probe fails */
hwif->major = ide_hwif_to_major[h];
hwif->name[0] = 'i';
hwif->name[1] = 'd';
hwif->name[2] = 'e';
hwif->name[3] = '0' + h;
- hwif->name[4] = '\0';
- hwif->present = 0;
- hwif->next = NULL;
- hwif->reset_timeout = 0;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
- /* bulk initialize drive info with zeros */
- byte *p = ((byte *) drive) + sizeof(ide_drive_t);
- do {
- *--p = 0;
- } while (p > (byte *) drive);
-
/* fill in any non-zero initial values */
drive->select.all = (unit<<4)|0xa0;
drive->hwif = hwif;
#ifdef __i386__
#define VLB_SYNC 1
-
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data. We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
static inline void do_vlb_sync (unsigned short port) {
unsigned int _v;
__asm__ __volatile__ (
}
/*
- * ide_alloc(): memory allocation for using during driver initialization.
+ * ide_alloc(): memory allocation for use *only* during driver initialization.
+ * If "within_area" is non-zero, the memory will be allocated such that
+ * it lies entirely within a "within_area" sized area (eg. 4096). This is
+ * needed for DMA stuff. "within_area" must be a power of two (not validated).
+ * All allocations are longword aligned.
*/
-static unsigned long init_mem_start = 0uL; /* used by init routines */
+static unsigned long ide_mem_start = 0uL; /* used by ide_alloc() */
-static inline void *ide_alloc (unsigned long bytecount)
+void *ide_alloc (unsigned long bytecount, unsigned long within_area)
{
- unsigned long p = init_mem_start;
- if (!p) panic("ide: ide_alloc() not valid now\n");
- init_mem_start += (bytecount + 3uL) & ~3uL;
- return (void *) p;
+ const unsigned long longsize_m1 = (sizeof(long) - 1);
+ void *p;
+
+ if (!ide_mem_start)
+ panic("ide: ide_alloc() not valid now\n");
+ ide_mem_start = (ide_mem_start + longsize_m1) & ~longsize_m1;
+ if (within_area) {
+ unsigned long fraction = within_area - (ide_mem_start & (within_area - 1));
+ if (fraction < bytecount)
+ ide_mem_start += fraction; /* realign to a new page */
+ }
+ p = (void *) ide_mem_start;
+ ide_mem_start += (bytecount + longsize_m1) & ~longsize_m1;
+ return p;
}
/*
break;
}
minors = units * (1<<PARTN_BITS);
- gd = ide_alloc(sizeof(struct gendisk));
- gd->sizes = ide_alloc(minors * sizeof(int));
- gd->part = ide_alloc(minors * sizeof(struct hd_struct));
- bs = ide_alloc(minors*sizeof(int));
+ gd = ide_alloc (sizeof(struct gendisk), 0);
+ gd->sizes = ide_alloc (minors * sizeof(int), 0);
+ gd->part = ide_alloc (minors * sizeof(struct hd_struct), 0);
+ bs = ide_alloc (minors*sizeof(int), 0);
/* cdroms and msdos f/s are examples of non-1024 blocksizes */
blksize_size[hwif->major] = bs;
*/
static void reset_ihandler (ide_drive_t *drive)
{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
unexpected_intr (HWIF(drive)->irq, HWGROUP(drive));
+ restore_flags(flags);
}
/*
{
ide_hwgroup_t *hwgroup = hwif->hwgroup;
- hwif->reset_timeout = jiffies + WAIT_WORSTCASE; /* max waiting time */
+ hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE; /* max waiting time */
hwgroup->handler = &reset_ihandler; /* dummy irq handler */
hwgroup->timer.expires = jiffies + (HZ/20); /* polling interval */
add_timer(&(hwgroup->timer));
}
+#ifdef CONFIG_BLK_DEV_IDECD
+/*
+ * atapi_reset_handler() gets invoked to poll the interface for completion every 50ms
+ * during an atapi drive reset operation. If the drive has not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ *
+ * Returns 1 if waiting for another 50ms, returns 0 otherwise.
+ */
+static int atapi_reset_handler (ide_hwgroup_t *hwgroup)
+{
+ ide_hwif_t *hwif = hwgroup->hwif;
+ ide_drive_t *drive = hwgroup->drive;
+ byte stat;
+
+ OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+ udelay (10);
+
+ if (!OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
+ if (jiffies < hwgroup->reset_timeout) {
+ start_reset_timer (hwif);
+ return 1;
+ }
+ printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
+ return ide_do_reset (drive); /* do it the old fashioned way */
+ }
+ hwgroup->doing_atapi_reset = 0;
+ hwgroup->handler = NULL; /* allow new requests to be processed */
+ hwgroup->reset_timeout = 0; /* signal end of ide reset operation */
+ printk("%s: ATAPI reset complete\n", drive->name);
+ return 0;
+}
+#endif /* CONFIG_BLK_DEV_IDECD */
+
/*
* reset_handler() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not not responded,
+ * during an ide reset operation. If the drives have not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*
ide_drive_t *drive = hwgroup->drive;
byte tmp;
+#ifdef CONFIG_BLK_DEV_IDECD
+ if (hwgroup->doing_atapi_reset)
+ return atapi_reset_handler(hwgroup);
+#endif /* CONFIG_BLK_DEV_IDECD */
+
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
- if (jiffies < hwif->reset_timeout) {
+ if (jiffies < hwgroup->reset_timeout) {
start_reset_timer (hwif);
return 1;
}
}
}
hwgroup->handler = NULL; /* allow new requests to be processed */
- hwif->reset_timeout = 0; /* signal end of ide reset operation */
+ hwgroup->reset_timeout = 0; /* signal end of ide reset operation */
return 0;
}
* the same interface, so it can really be thought of as resetting the
* interface rather than resetting the drive.
*
- * ATAPI devices have their own reset mechanism (not handled here),
- * which allows them to be individually reset without clobbering other
- * devices on the same interface. ide-cd.c will handle those separately.
+ * ATAPI devices have their own reset mechanism which allows them to be
+ * individually reset without clobbering other devices on the same interface.
*
* Unfortunately, the IDE interface does not generate an interrupt to let
* us know when the reset operation has finished, so we must poll for this.
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals.
*/
-static int ide_do_reset (ide_drive_t *drive)
+int ide_do_reset (ide_drive_t *drive)
{
unsigned int unit;
unsigned long flags;
ide_hwif_t *hwif = HWIF(drive);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
save_flags(flags);
cli(); /* Why ? */
+#ifdef CONFIG_BLK_DEV_IDECD
+ /* For an ATAPI device, first try an ATAPI SRST. */
+ if (drive->media == cdrom) {
+ if (!hwgroup->doing_atapi_reset) {
+ hwgroup->doing_atapi_reset = 1;
+ if (!drive->keep_settings)
+ drive->unmask = 0;
+ OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+ OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
+ udelay (10);
+ hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
+ start_reset_timer (hwif); /* begin periodic polling */
+ restore_flags (flags);
+ return 1;
+ }
+ }
+ hwgroup->doing_atapi_reset = 0;
+#endif /* CONFIG_BLK_DEV_IDECD */
+
/*
* First, reset any device state data we were maintaining
* for any of the drives on this interface.
* This single interrupt gives us a "fast poll" for drives that
* recover from reset very quickly, saving us the first 50ms wait time.
*/
- OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set nIEN and SRST */
+ OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */
udelay(5); /* more than enough time */
OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
- hwif->reset_timeout = jiffies + WAIT_WORSTCASE;
+ hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
start_reset_timer (hwif); /* begin periodic polling */
#endif /* OK_TO_RESET_CONTROLLER */
printk("Busy ");
else {
if (stat & READY_STAT) printk("DriveReady ");
- if (stat & WRERR_STAT) printk("WriteFault ");
+ if (stat & WRERR_STAT) printk("DeviceFault ");
if (stat & SEEK_STAT) printk("SeekComplete ");
if (stat & DRQ_STAT) printk("DataRequest ");
if (stat & ECC_STAT) printk("CorrectedError ");
if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
rq->errors |= ERROR_RESET; /* Mmmm.. timing problem */
+ if (rq->errors > 3 && drive->using_dma) { /* DMA troubles? */
+ drive->using_dma = 0;
+ printk("%s: DMA disabled\n", drive->name);
+ --rq->errors;
+ return 0;
+ }
if (rq->errors >= ERROR_MAX)
ide_end_request(0, HWGROUP(drive));
else {
* Issue a simple drive command
* The drive must be selected beforehand.
*/
-static inline void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
+static void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
{
ide_set_handler (drive, handler);
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
OUT_BYTE(cmd,IDE_COMMAND_REG);
}
+/*
+ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ */
static void set_multmode_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
IDE_DO_REQUEST;
}
+/*
+ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ */
static void set_geometry_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
IDE_DO_REQUEST;
}
+/*
+ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ */
static void recal_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
IDE_DO_REQUEST;
}
+#ifdef IDE_DRIVE_CMD
+/*
+ * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+ */
static void drive_cmd_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
return;
IDE_DO_REQUEST;
}
+#endif /* IDE_DRIVE_CMD */
-static void do_special (ide_drive_t *drive)
+/*
+ * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
+ * commands to a drive. It used to do much more, but has been scaled back
+ * in recent updates, and could be completely eliminated with a bit more effort.
+ */
+static inline void do_special (ide_drive_t *drive)
{
special_t *s = &drive->special;
#ifdef DEBUG
return 1;
}
+/*
+ * do_rw_disk() issues WIN_{MULT}READ and WIN_{MULT}WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors. It also takes
+ * care of issuing special DRIVE_CMDs.
+ */
static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
#endif
}
if (rq->cmd == READ) {
+ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+ return;
ide_set_handler(drive, &read_intr);
OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
return;
}
if (rq->cmd == WRITE) {
+ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
+ return;
OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
printk("%s: no DRQ after issuing %s\n", drive->name,
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
return;
} else {
+ /*
+ * NULL is actually a valid way of waiting for
+ * all current requests to be flushed from the queue.
+ */
#ifdef DEBUG
printk("%s: DRIVE_CMD (null)\n", drive->name);
#endif
ide_end_request(0, HWGROUP(drive));
}
+/*
+ * do_request() initiates handling of a new I/O request
+ */
static inline void do_request (ide_hwif_t *hwif, struct request *rq)
{
unsigned int minor, unit;
goto kill_rq;
}
drive = &hwif->drives[unit];
+#ifdef DEBUG
if (rq->bh && !rq->bh->b_lock) {
printk("%s: block not locked\n", drive->name);
goto kill_rq;
}
+#endif
block = rq->sector;
blockend = block + rq->nr_sectors;
if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
- printk("%s: bad access: block=%ld, count=%ld\n",
- drive->name, block, rq->nr_sectors);
+ printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
+ (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
goto kill_rq;
}
block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
+ ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
#if (DISK_RECOVERY_TIME > 0)
while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
#endif
return;
}
- ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
if (!drive->special.all) {
#ifdef CONFIG_BLK_DEV_IDECD
switch (drive->media) {
void ide_do_request (ide_hwgroup_t *hwgroup)
{
cli(); /* paranoia */
-
if (hwgroup->handler != NULL) {
printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name);
return;
goto got_rq;
} while ((hwif = hwif->next) != hwgroup->hwif);
return; /* no work left for this hwgroup */
+ got_rq:
+ blk_dev[hwif->major].current_request = rq->next;
}
- got_rq:
- blk_dev[hwif->major].current_request = rq->next;
do_request(hwgroup->hwif = hwif, hwgroup->rq = rq);
cli();
} while (hwgroup->handler == NULL);
}
+/*
+ * do_hwgroup_request() invokes ide_do_request() after first masking
+ * all possible interrupts for the current hwgroup. This prevents race
+ * conditions in the event that an unexpected interrupt occurs while
+ * we are in the driver.
+ *
+ * Note that when an interrupt is used to reenter the driver, the first level
+ * handler will already have masked the irq that triggered, but any other ones
+ * for the hwgroup will still be unmasked. The driver tries to be careful
+ * about such things.
+ */
static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
{
if (hwgroup->handler == NULL) {
save_flags(flags);
cli();
- if (hwgroup->hwif->reset_timeout != 0) { /* ide reset in progress? */
+ if (hwgroup->reset_timeout != 0) { /* ide reset in progress? */
if (!reset_handler(hwgroup))
do_hwgroup_request (hwgroup);
} else if (hwgroup->handler == NULL) { /* not waiting for anything? */
printk("%s: marginal timeout\n", drive->name);
} else { /* drive not responding */
hwgroup->handler = NULL;
+ if (hwgroup->hwif->dmaproc)
+ (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
if (!ide_error(drive, "irq timeout", GET_STAT()))
do_hwgroup_request (hwgroup);
}
* On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
* drive enters "idle", "standby", or "sleep" mode, so if the status looks
* "good", we just ignore the interrupt completely.
+ *
+ * This routine assumes cli() is in effect when called.
+ *
+ * If an unexpected interrupt happens on irq15 while we are handling irq14
+ * and if the two interfaces are "serialized" (CMD640B), then it looks like
+ * we could screw up by interfering with a new request being set up for irq15.
+ *
+ * In reality, this is a non-issue. The new command is not sent unless the
+ * drive is ready to accept one, in which case we know the drive is not
+ * trying to interrupt us. And ide_set_handler() is always invoked before
+ * completing the issuance of any new drive command, so we will not be
+ * accidently invoked as a result of any valid command completion interrupt.
+ *
*/
static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
{
byte stat;
unsigned int unit;
ide_hwif_t *hwif = hwgroup->hwif;
- unsigned long flags;
-
- save_flags(flags);
- cli();
/*
* check for ide reset in progress
*/
- if (hwif->reset_timeout != 0) {
+ if (hwgroup->reset_timeout != 0) {
if (!reset_handler(hwgroup))
do_hwgroup_request (hwgroup);
- restore_flags(flags);
return;
}
}
}
} while ((hwif = hwif->next) != hwgroup->hwif);
- restore_flags(flags);
}
/*
{
ide_hwgroup_t *hwgroup = irq_to_hwgroup[irq];
ide_handler_t *handler;
- if (irq != hwgroup->hwif->irq) {
-#ifdef DEBUG
- printk("ide_intr: expected ira %d, got irq %d instead\n",
- hwgroup->hwif->irq, irq);
-#endif
- unexpected_intr(irq, hwgroup);
- } else if ((handler = hwgroup->handler) != NULL) {
+
+ if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) {
ide_drive_t *drive = hwgroup->drive;
hwgroup->handler = NULL;
del_timer(&(hwgroup->timer));
sti();
handler(drive);
} else {
- sti();
unexpected_intr(irq, hwgroup);
}
cli();
}
+/*
+ * get_info_ptr() returns the (ide_drive_t *) for a given device number.
+ * It returns NULL if the given device number does not match any present drives.
+ */
static ide_drive_t *get_info_ptr (int i_rdev)
{
int major = MAJOR(i_rdev);
}
#ifdef IDE_DRIVE_CMD
-static int write_fs_long (unsigned long useraddr, long value)
-{
- int err;
-
- if (NULL == (long *)useraddr)
- return -EINVAL;
- if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
- return err;
- put_user((unsigned)value, (long *) useraddr);
- return 0;
-}
-
/*
* This function issues a specific IDE drive command onto the
* tail of the request queue, and waits for it to be completed.
if ((drive = get_info_ptr(i_rdev)) == NULL)
return -ENODEV;
- major = MAJOR(i_rdev);
+ major = MAJOR(i_rdev) << 8;
minor = drive->select.b.unit << PARTN_BITS;
save_flags(flags);
cli();
return 0;
}
+static int write_fs_long (unsigned long useraddr, long value)
+{
+ int err;
+
+ if (NULL == (long *)useraddr)
+ return -EINVAL;
+ if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
+ return err;
+ put_user((unsigned)value, (long *) useraddr);
+ return 0;
+}
+
static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
case HDIO_GET_UNMASKINTR:
return write_fs_long(arg, drive->unmask);
+ case HDIO_GET_DMA:
+ return write_fs_long(arg, drive->using_dma);
+
case HDIO_GET_CHIPSET:
return write_fs_long(arg, drive->chipset);
if (drive->id == NULL)
return -ENOMSG;
err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*drive->id));
- if (err) return err;
- memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
- return 0;
+ if (!err)
+ memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
+ return err;
case HDIO_GET_NOWERR:
return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT);
+ case HDIO_SET_DMA:
+ if (drive->media != disk)
+ return -EPERM;
+ if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+ return -EPERM;
case HDIO_SET_KEEPSETTINGS:
case HDIO_SET_UNMASKINTR:
case HDIO_SET_NOWERR:
save_flags(flags);
cli();
switch (cmd) {
+ case HDIO_SET_DMA:
+ drive->using_dma = arg;
+ break;
case HDIO_SET_KEEPSETTINGS:
drive->keep_settings = arg;
break;
return 0;
case HDIO_SET_MULTCOUNT:
- if (!suser()) return -EACCES;
+ if (!suser())
+ return -EACCES;
if (inode->i_rdev & PARTN_MASK)
return -EINVAL;
if ((drive->id != NULL) && (arg > drive->id->max_multsect))
*p++ = '\0';
}
-static void do_identify (ide_drive_t *drive, byte cmd)
+static inline void do_identify (ide_drive_t *drive, byte cmd)
{
int bswap;
struct hd_driveid *id;
unsigned long capacity, check;
- id = drive->id = ide_alloc(SECTOR_WORDS*4);
+ id = drive->id = ide_alloc (SECTOR_WORDS*4, 0);
ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */
sti();
*/
bswap = 1;
if (cmd == WIN_PIDENTIFY) {
- if ((id->model[0] == 'N' && id->model[1] == 'E')
- || (id->model[0] == 'F' && id->model[1] == 'X')
- || (id->model[0] == 'P' && id->model[1] == 'i'))
- bswap = 0; /* NEC, Pioneer and *some* Mitsumi units */
- } /* Vertos drives may still be weird */
+ if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
+ || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
+ || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
+ bswap = 0; /* Vertos drives may still be weird */
+ }
fixstring (id->model, sizeof(id->model), bswap);
fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
fixstring (id->serial_no, sizeof(id->serial_no), bswap);
drive->mult_req = id->max_multsect;
if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
drive->special.b.set_multmode = 1;
- printk(", MaxMult=%d", id->max_multsect);
+ }
+ if (HWIF(drive)->dmaproc != NULL) { /* hwif supports DMA? */
+ if (!(HWIF(drive)->dmaproc(ide_dma_check, drive)))
+ printk(", DMA");
}
printk("\n");
}
* Returns: 0 no device was found
* 1 device was found (note: drive->present might still be 0)
*/
-static byte probe_for_drive (ide_drive_t *drive)
+static inline byte probe_for_drive (ide_drive_t *drive)
{
if (drive->noprobe) /* skip probing? */
return drive->present;
* 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value
* means we have an AT controller hard disk for that drive.
*/
+
static void probe_cmos_for_drives (ide_hwif_t *hwif)
{
#ifdef __i386__
ide_drive_t *drive = &hwif->drives[unit];
if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present) {
drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS;
- drive->head = drive->bios_head = * (BIOS+2);
- drive->sect = drive->bios_sect = * (BIOS+14);
- drive->wpcom = (*(unsigned short *)(BIOS+5))>>2;
+ drive->head = drive->bios_head = *(BIOS+2);
+ drive->sect = drive->bios_sect = *(BIOS+14);
drive->ctl = *(BIOS+8);
- drive->wpcom = 0;
drive->media = disk;
drive->present = 1;
}
* Got the irq, now set everything else up
*/
if ((hwgroup = irq_to_hwgroup[hwif->irq]) == NULL) {
- hwgroup = ide_alloc(sizeof(ide_hwgroup_t));
+ hwgroup = ide_alloc (sizeof(ide_hwgroup_t), 0);
irq_to_hwgroup[hwif->irq] = hwgroup;
hwgroup->hwif = hwif->next = hwif;
hwgroup->rq = NULL;
hwgroup->handler = NULL;
hwgroup->drive = NULL;
+ hwgroup->reset_timeout = 0;
+#ifdef CONFIG_BLK_DEV_IDECD
+ hwgroup->doing_atapi_reset = 0;
+#endif /* CONFIG_BLK_DEV_IDECD */
init_timer(&hwgroup->timer);
hwgroup->timer.function = &timer_expiry;
hwgroup->timer.data = (unsigned long) hwgroup;
}
#endif /* SUPPORT_DTC2278 */
+
/*
* This is gets invoked once during initialization, to set *everything* up
*/
{
int h;
- init_mem_start = (mem_start + 3uL) & ~3uL; /* for ide_alloc() */
+ ide_mem_start = mem_start; /* for ide_alloc () */
init_ide_data ();
/*
* First, we determine what hardware is present
if (probe_dtc2278)
try_to_init_dtc2278();
#endif /* SUPPORT_DTC2278 */
+#ifdef CONFIG_PCI
+ /*
+ * Look for pci disk interfaces.
+ */
+ if (pcibios_present()) {
+#ifdef CONFIG_BLK_DEV_TRITON
+ ide_init_triton (ide_hwifs);
+#endif /* CONFIG_BLK_DEV_TRITON */
+ }
+#endif /* CONFIG_PCI */
+
+ /*
+ * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
+ */
for (h = 0; h < MAX_HWIFS; ++h) {
ide_hwif_t *hwif = &ide_hwifs[h];
if (!hwif->noprobe) {
if (hwif->irq == HD_IRQ && hwif->io_base != HD_DATA) {
printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
hwif->present = 0;
+B
}
#endif /* CONFIG_BLK_DEV_HD */
}
hwif->present = 1; /* success */
}
}
- mem_start = init_mem_start;
- init_mem_start = 0uL; /* prevent further use of ide_alloc() */
+ mem_start = ide_mem_start;
+ ide_mem_start = 0uL; /* prevent further use of ide_alloc() */
return mem_start;
}
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <asm/io.h>
-#define REALLY_FAST_IO /* define if ide ports are perfect */
+#undef REALLY_FAST_IO /* define if ide ports are perfect */
#define INITIAL_MULT_COUNT 0 /* off=0; on=2,4,8,16,32, etc.. */
#ifndef DISK_RECOVERY_TIME /* off=0; on=access_delay_time */
#ifdef CONFIG_BLK_DEV_IDECD
-struct packet_command {
- char *buffer;
- int buflen;
- int stat;
- unsigned char c[12];
-};
-
-
struct atapi_request_sense {
unsigned char error_code : 7;
unsigned char valid : 1;
byte sense_key_specific[3];
};
+struct packet_command {
+ char *buffer;
+ int buflen;
+ int stat;
+ struct atapi_request_sense *sense_data;
+ unsigned char c[12];
+};
+
/* Space to hold the disk TOC. */
#define MAX_TRACKS 99
};
struct atapi_toc {
+ int last_session_lba;
+ int xa_flag;
+ unsigned capacity;
struct atapi_toc_header hdr;
struct atapi_toc_entry ent[MAX_TRACKS+1]; /* One extra for the leadout. */
};
unsigned vlb_32bit : 1; /* use 32bit in/out for data */
unsigned vlb_sync : 1; /* needed for some 32bit chip sets */
unsigned removeable : 1; /* 1 if need to do check_media_change */
- unsigned dma_capable : 1; /* for Intel Triton chipset, others.. */
+ unsigned using_dma : 1; /* disk is using dma for read/write */
+ unsigned unmask : 1; /* flag: okay to unmask other irqs */
+ media_t media; /* disk, cdrom, tape */
select_t select; /* basic drive/head select reg value */
- byte unmask; /* flag: okay to unmask other irqs */
void *hwif; /* actually (ide_hwif_t *) */
byte ctl; /* "normal" value for IDE_CONTROL_REG */
byte ready_stat; /* min status value for drive ready */
- byte wpcom; /* ignored by all IDE drives */
- media_t media; /* disk, cdrom, tape */
byte mult_count; /* current multiple sector setting */
byte mult_req; /* requested multiple sector setting */
byte chipset; /* interface chipset access method */
#endif /* CONFIG_BLK_DEV_IDECD */
} ide_drive_t;
+/*
+ * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA. All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case the caller
+ * should either try again later, or revert to PIO for the current request.
+ */
+typedef enum {ide_dma_read = 0, ide_dma_write = 1, ide_dma_abort = 2, ide_dma_check = 3} ide_dma_action_t;
+typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
+
typedef struct hwif_s {
struct hwif_s *next; /* for linked-list in ide_hwgroup_t */
void *hwgroup; /* actually (ide_hwgroup_t *) */
unsigned short io_base; /* base io port addr */
unsigned short ctl_port; /* usually io_base+0x206 */
- ide_drive_t drives[MAX_DRIVES]; /* drive info */
+ ide_drive_t drives[MAX_DRIVES]; /* drive info */
struct gendisk *gd; /* gendisk structure */
+ ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */
+ unsigned long *dmatable; /* dma physical region descriptor table */
+ unsigned short dma_base; /* base addr for dma ports (triton) */
byte irq; /* our irq number */
byte major; /* our major number */
byte drivecount; /* how many drives attached */
char name[5]; /* name of interface, eg. "ide0" */
unsigned noprobe : 1; /* don't probe for this interface */
unsigned present : 1; /* this interface exists */
- unsigned long reset_timeout; /* timeout value during ide resets */
#if (DISK_RECOVERY_TIME > 0)
- unsigned long last_timer; /* time when previous rq was done */
+ unsigned long last_time; /* time when previous rq was done */
#endif
#ifdef CONFIG_BLK_DEV_IDECD
struct request request_sense_request; /* from ide-cd.c */
} ide_hwif_t;
/*
- * our internal interrupt handler type
+ * internal ide interrupt handler type
*/
typedef void (ide_handler_t)(ide_drive_t *);
struct request *rq; /* current request */
struct timer_list timer; /* failsafe timer */
struct request wrq; /* local copy of current write rq */
+ unsigned long reset_timeout; /* timeout value during ide resets */
+#ifdef CONFIG_BLK_DEV_IDECD
+ int doing_atapi_reset;
+#endif /* CONFIG_BLK_DEV_IDECD */
} ide_hwgroup_t;
/*
*/
int ide_xlate_1024(dev_t, int, const char *);
+/*
+ * Start a reset operation for an IDE interface.
+ * Returns 0 if the reset operation is still in progress,
+ * in which case the drive MUST return, to await completion.
+ * Returns 1 if the reset is complete (success or failure).
+ */
+int ide_do_reset (ide_drive_t *);
+
+/*
+ * ide_alloc(): memory allocation for use *only* during driver initialization.
+ * If "within_area" is non-zero, the memory will be allocated such that
+ * it lies entirely within a "within_area" sized area (eg. 4096). This is
+ * needed for DMA stuff. "within_area" must be a power of two (not validated).
+ * All allocations are longword aligned.
+ */
+void *ide_alloc (unsigned long bytecount, unsigned long within_area);
+
#ifdef CONFIG_BLK_DEV_IDECD
/*
* These are routines in ide-cd.c invoked from ide.c
void ide_cdrom_release (struct inode *, struct file *, ide_drive_t *);
void ide_cdrom_setup (ide_drive_t *);
#endif /* CONFIG_BLK_DEV_IDECD */
+
+#ifdef CONFIG_BLK_DEV_TRITON
+void ide_init_triton (ide_hwif_t *);
+#endif /* CONFIG_BLK_DEV_TRITON */
+
-/* $Id: optcd.c,v 1.7 1995/06/28 20:20:13 root Exp $
+/* $Id: optcd.c,v 1.3 1995/08/24 19:54:27 root Exp root $
linux/drivers/block/optcd.c - Optics Storage 8000 AT CDROM driver
Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks
- by Eberhard Moenkeberg.
+ by Eberhard Moenkeberg (emoenke@gwdg.de). ISP16 detection and
+ configuration by Eric van der Maarel (maarel@marin.nl), with some data
+ communicated by Vadim V. Model (vadim@rbrf.msk.su).
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
should go into its own driver. The driver now
has its own major nr.
Disk change detection now seems to work, too.
+ This version became part of the standard
+ kernel as of version 1.3.7
+ 24-9-95 v0.4 Re-inserted ISP-16 interface code which I
+ copied from sjcd.c, with a few changes.
+ Updated README.optcd. Submitted for
+ inclusion in 1.3.21
*/
#include <linux/major.h>
#define optcd_port optcd /* Needed for the modutils. */
# include <linux/optcd.h>
+
+/* Some (Media)Magic */
+/* define types of drive the interface on an ISP16 card may be looking at */
+#define ISP16_DRIVE_X 0x00
+#define ISP16_SONY 0x02
+#define ISP16_PANASONIC0 0x02
+#define ISP16_SANYO0 0x02
+#define ISP16_MITSUMI 0x04
+#define ISP16_PANASONIC1 0x06
+#define ISP16_SANYO1 0x06
+#define ISP16_DRIVE_NOT_USED 0x08 /* not used */
+#define ISP16_DRIVE_SET_MASK 0xF1 /* don't change 0-bit or 4-7-bits*/
+/* ...for port */
+#define ISP16_DRIVE_SET_PORT 0xF8D
+/* set io parameters */
+#define ISP16_BASE_340 0x00
+#define ISP16_BASE_330 0x40
+#define ISP16_BASE_360 0x80
+#define ISP16_BASE_320 0xC0
+#define ISP16_IRQ_X 0x00
+#define ISP16_IRQ_5 0x04 /* shouldn't be used due to soundcard conflicts */
+#define ISP16_IRQ_7 0x08 /* shouldn't be used due to soundcard conflicts */
+#define ISP16_IRQ_3 0x0C
+#define ISP16_IRQ_9 0x10
+#define ISP16_IRQ_10 0x14
+#define ISP16_IRQ_11 0x18
+#define ISP16_DMA_X 0x03
+#define ISP16_DMA_3 0x00
+#define ISP16_DMA_5 0x00
+#define ISP16_DMA_6 0x01
+#define ISP16_DMA_7 0x02
+#define ISP16_IO_SET_MASK 0x20 /* don't change 5-bit */
+/* ...for port */
+#define ISP16_IO_SET_PORT 0xF8E
+/* enable the drive */
+#define ISP16_NO_IDE__ENABLE_CDROM_PORT 0xF90 /* ISP16 without IDE interface */
+#define ISP16_IDE__ENABLE_CDROM_PORT 0xF91 /* ISP16 with IDE interface */
+#define ISP16_ENABLE_CDROM 0x80 /* seven bit */
+
+/* the magic stuff */
+#define ISP16_CTRL_PORT 0xF8F
+#define ISP16_NO_IDE__CTRL 0xE2 /* ISP16 without IDE interface */
+#define ISP16_IDE__CTRL 0xE3 /* ISP16 with IDE interface */
+
+static short isp16_detect(void);
+static short isp16_no_ide__detect(void);
+static short isp16_with_ide__detect(void);
+static short isp16_config( int base, u_char drive_type, int irq, int dma );
+static short isp16_type; /* dependent on type of interface card */
+static u_char isp16_ctrl;
+static u_short isp16_enable_cdrom_port;
+
+
static short optcd_port = OPTCD_PORTBASE;
/* Read current status/data availability flags */
optcd_port);
RETURN_EIO;
}
+
+ if (!check_region(ISP16_DRIVE_SET_PORT, 5)) {
+ /* If someone else has'nt already reserved these ports,
+ probe for an ISP16 interface card, and enable SONY mode
+ with no interrupts and no DMA. (As far as I know, all optics
+ drives come with a SONY interface.) */
+ if ( (isp16_type=isp16_detect()) < 0 )
+ printk( "No ISP16 cdrom interface found.\n" );
+ else {
+ u_char expected_drive;
+
+ printk( "ISP16 cdrom interface (%s optional IDE) detected.\n",
+ (isp16_type==2)?"with":"without" );
+
+ expected_drive = (isp16_type?ISP16_SANYO1:ISP16_SANYO0);
+
+ if ( isp16_config( optcd_port, ISP16_SONY, 0, 0 ) < 0 ) {
+ printk( "ISP16 cdrom interface has not been properly configured.\n" );
+ return(mem_start);
+ }
+ }
+ }
+
if (!optResetDrive()) {
printk("optcd: drive at 0x%x not ready\n", optcd_port);
RETURN_EIO;
printk("optcd: module released.\n");
}
#endif MODULE
+
+
+/*
+ * -- ISP16 detection and configuration
+ *
+ * Copyright (c) 1995, Eric van der Maarel <maarel@marin.nl>
+ *
+ * Version 0.5
+ *
+ * Detect cdrom interface on ISP16 soundcard.
+ * Configure cdrom interface.
+ *
+ * Algorithm for the card with no IDE support option taken
+ * from the CDSETUP.SYS driver for MSDOS,
+ * by OPTi Computers, version 2.03.
+ * Algorithm for the IDE supporting ISP16 as communicated
+ * to me by Vadim Model and Leo Spiekman.
+ *
+ * Use, modifification or redistribution of this software is
+ * allowed under the terms of the GPL.
+ *
+ */
+
+
+#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p))
+#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
+
+static short
+isp16_detect(void)
+{
+
+ if ( !( isp16_with_ide__detect() < 0 ) )
+ return(2);
+ else
+ return( isp16_no_ide__detect() );
+}
+
+static short
+isp16_no_ide__detect(void)
+{
+ u_char ctrl;
+ u_char enable_cdrom;
+ u_char io;
+ short i = -1;
+
+ isp16_ctrl = ISP16_NO_IDE__CTRL;
+ isp16_enable_cdrom_port = ISP16_NO_IDE__ENABLE_CDROM_PORT;
+
+ /* read' and write' are a special read and write, respectively */
+
+ /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */
+ ctrl = ISP16_IN( ISP16_CTRL_PORT ) & 0xFC;
+ ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+
+ /* read' 3,4 and 5-bit from the cdrom enable port */
+ enable_cdrom = ISP16_IN( ISP16_NO_IDE__ENABLE_CDROM_PORT ) & 0x38;
+
+ if ( !(enable_cdrom & 0x20) ) { /* 5-bit not set */
+ /* read' last 2 bits of ISP16_IO_SET_PORT */
+ io = ISP16_IN( ISP16_IO_SET_PORT ) & 0x03;
+ if ( ((io&0x01)<<1) == (io&0x02) ) { /* bits are the same */
+ if ( io == 0 ) { /* ...the same and 0 */
+ i = 0;
+ enable_cdrom |= 0x20;
+ }
+ else { /* ...the same and 1 */ /* my card, first time 'round */
+ i = 1;
+ enable_cdrom |= 0x28;
+ }
+ ISP16_OUT( ISP16_NO_IDE__ENABLE_CDROM_PORT, enable_cdrom );
+ }
+ else { /* bits are not the same */
+ ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+ return(i); /* -> not detected: possibly incorrect conclusion */
+ }
+ }
+ else if ( enable_cdrom == 0x20 )
+ i = 0;
+ else if ( enable_cdrom == 0x28 ) /* my card, already initialised */
+ i = 1;
+
+ ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+
+ return(i);
+}
+
+static short
+isp16_with_ide__detect(void)
+{
+ u_char ctrl;
+ u_char tmp;
+
+ isp16_ctrl = ISP16_IDE__CTRL;
+ isp16_enable_cdrom_port = ISP16_IDE__ENABLE_CDROM_PORT;
+
+ /* read' and write' are a special read and write, respectively */
+
+ /* read' ISP16_CTRL_PORT and save */
+ ctrl = ISP16_IN( ISP16_CTRL_PORT );
+
+ /* write' zero to the ctrl port and get response */
+ ISP16_OUT( ISP16_CTRL_PORT, 0 );
+ tmp = ISP16_IN( ISP16_CTRL_PORT );
+
+ if ( tmp != 2 ) /* isp16 with ide option not detected */
+ return(-1);
+
+ /* restore ctrl port value */
+ ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+
+ return(2);
+}
+
+static short
+isp16_config( int base, u_char drive_type, int irq, int dma )
+{
+ u_char base_code;
+ u_char irq_code;
+ u_char dma_code;
+ u_char i;
+
+ if ( (drive_type == ISP16_MITSUMI) && (dma != 0) )
+ printk( "Mitsumi cdrom drive has no dma support.\n" );
+
+ switch (base) {
+ case 0x340: base_code = ISP16_BASE_340; break;
+ case 0x330: base_code = ISP16_BASE_330; break;
+ case 0x360: base_code = ISP16_BASE_360; break;
+ case 0x320: base_code = ISP16_BASE_320; break;
+ default:
+ printk( "Base address 0x%03X not supported by cdrom interface on ISP16.\n", base );
+ return(-1);
+ }
+ switch (irq) {
+ case 0: irq_code = ISP16_IRQ_X; break; /* disable irq */
+ case 5: irq_code = ISP16_IRQ_5;
+ printk( "Irq 5 shouldn't be used by cdrom interface on ISP16,"
+ " due to possible conflicts with the soundcard.\n");
+ break;
+ case 7: irq_code = ISP16_IRQ_7;
+ printk( "Irq 7 shouldn't be used by cdrom interface on ISP16,"
+ " due to possible conflicts with the soundcard.\n");
+ break;
+ case 3: irq_code = ISP16_IRQ_3; break;
+ case 9: irq_code = ISP16_IRQ_9; break;
+ case 10: irq_code = ISP16_IRQ_10; break;
+ case 11: irq_code = ISP16_IRQ_11; break;
+ default:
+ printk( "Irq %d not supported by cdrom interface on ISP16.\n", irq );
+ return(-1);
+ }
+ switch (dma) {
+ case 0: dma_code = ISP16_DMA_X; break; /* disable dma */
+ case 1: printk( "Dma 1 cannot be used by cdrom interface on ISP16,"
+ " due to conflict with the soundcard.\n");
+ return(-1); break;
+ case 3: dma_code = ISP16_DMA_3; break;
+ case 5: dma_code = ISP16_DMA_5; break;
+ case 6: dma_code = ISP16_DMA_6; break;
+ case 7: dma_code = ISP16_DMA_7; break;
+ default:
+ printk( "Dma %d not supported by cdrom interface on ISP16.\n", dma );
+ return(-1);
+ }
+
+ if ( drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 &&
+ drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 &&
+ drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI &&
+ drive_type != ISP16_DRIVE_X ) {
+ printk( "Drive type (code 0x%02X) not supported by cdrom"
+ " interface on ISP16.\n", drive_type );
+ return(-1);
+ }
+
+ /* set type of interface */
+ i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK; /* clear some bits */
+ ISP16_OUT( ISP16_DRIVE_SET_PORT, i|drive_type );
+
+ /* enable cdrom on interface with ide support */
+ if ( isp16_type > 1 )
+ ISP16_OUT( isp16_enable_cdrom_port, ISP16_ENABLE_CDROM );
+
+ /* set base address, irq and dma */
+ i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK; /* keep some bits */
+ ISP16_OUT( ISP16_IO_SET_PORT, i|base_code|irq_code|dma_code );
+
+ return(0);
+}
--- /dev/null
+/*
+ * linux/drivers/block/triton.c Version 1.00 Aug 26, 1995
+ *
+ * Copyright (c) 1995 Mark Lord
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This module provides support for the Bus Master IDE DMA function
+ * of the Intel PCI Triton chipset (82371FB).
+ *
+ * DMA is currently supported only for hard disk drives (not cdroms).
+ *
+ * Support for cdroms will likely be added at a later date,
+ * after broader experience has been obtained with hard disks.
+ *
+ * Up to four drives may be enabled for DMA, and the Triton chipset will
+ * (hopefully) arbitrate the PCI bus among them. Note that the 82371FB chip
+ * provides a single "line buffer" for the BM IDE function, so performance of
+ * multiple (two) drives doing DMA simultaneously will suffer somewhat,
+ * as they contest for that resource bottleneck. This is handled transparently
+ * inside the 82371FB chip.
+ *
+ * By default, DMA support is prepared for use, but is currently enabled only
+ * for drives which support multi-word DMA mode2 (mword2), or which are
+ * recognized as "good" (see table below). Drives with only mode0 or mode1
+ * (single or multi) DMA should also work with this chipset/driver (eg. MC2112A)
+ * but are not enabled by default. Use "hdparm -i" to view supported modes
+ * for a given drive.
+ *
+ * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling
+ * DMA support, but must be (re-)compiled against this kernel version or later.
+ *
+ * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
+ * If problems arise, ide.c will disable DMA operation after a few retries.
+ * This error recovery mechanism works and has been extremely well exercised.
+ *
+ * IDE drives, depending on their vintage, may support several different modes
+ * of DMA operation. The boot-time modes are indicated with a "*" in
+ * the "hdparm -i" listing, and can be changed with *knowledgeable* use of
+ * the "hdparm -X" feature. There is seldom a need to do this, as drives
+ * normally power-up with their "best" PIO/DMA modes enabled.
+ *
+ * Testing was done with an ASUS P55TP4XE/100 system and the following drives:
+ *
+ * Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4.
+ * - DMA mode2 works fine (7.4MB/sec), despite the tiny on-drive buffer.
+ * - This drive also does PIO mode4, slightly slower than DMA mode2.
+ *
+ * Micropolis MC2112A (1Gig w/512kB buffer), drive pre-dates EIDE, ATA2.
+ * - DMA works fine (2.2MB/sec), probably due to the large on-drive buffer.
+ * - This older drive can also be tweaked for fastPIO (3,7MB/sec) by using
+ * maximum clock settings (5,4) and setting all flags except prefetch.
+ *
+ * Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3.
+ * - DMA does not work reliably. The drive appears to be somewhat tardy
+ * in deasserting DMARQ at the end of a sector. This is evident in
+ * the observation that WRITEs work most of the time, depending on
+ * cache-buffer occupancy, but multi-sector reads seldom work.
+ *
+ * Drives like the AC31000H could likely be made to work if all DMA were done
+ * one sector at a time, but that would likely negate any advantage over PIO.
+ *
+ * If you have any drive models add, email your results to: mlord@bnr.ca
+ * Keep an eye on your /var/adm/messages for "DMA disabled" messages.
+ */
+#define _TRITON_C
+#include <linux/config.h>
+#ifndef CONFIG_BLK_DEV_TRITON
+#define CONFIG_BLK_DEV_TRITON y
+#endif
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/io.h>
+
+#include "ide.h"
+
+/*
+ * good_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which do not support mword2 DMA but which are
+ * known to work fine with this interface under Linux.
+ */
+const char *good_dma_drives[] = {"Micropolis 2112A"};
+
+/*
+ * Our Physical Region Descriptor (PRD) table should be large enough
+ * to handle the biggest I/O request we are likely to see. Since requests
+ * can have no more than 256 sectors, and since the typical blocksize is
+ * two sectors, we can get by with a limit of 128 entries here for the
+ * usual worst case. Most requests seem to include some contiguous blocks,
+ * further reducing the number of table entries required.
+ *
+ * Note that the driver reverts to PIO mode for individual requests that exceed
+ * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
+ * 100% of all crazy scenarios here is not necessary.
+ */
+#define PRD_ENTRIES 128 /* max memory area count per DMA */
+
+/*
+ * dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static void dma_intr (ide_drive_t *drive)
+{
+ byte stat, dma_stat;
+ int i;
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned short dma_base = HWIF(drive)->dma_base;
+
+ dma_stat = inb(dma_base+2); /* get DMA status */
+ outb(inb(dma_base)&~1, dma_base); /* stop DMA operation */
+ stat = GET_STAT();
+ if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+ if ((dma_stat & 7) == 4) { /* verify good DMA status */
+ rq = HWGROUP(drive)->rq;
+ for (i = rq->nr_sectors; i > 0;) {
+ i -= rq->current_nr_sectors;
+ ide_end_request(1, HWGROUP(drive));
+ }
+ IDE_DO_REQUEST;
+ return;
+ }
+ printk("%s: bad DMA status: 0x%02x\n", drive->name, dma_stat);
+ }
+ sti();
+ if (!ide_error(drive, "dma_intr", stat))
+ IDE_DO_REQUEST;
+}
+
+/*
+ * build_dmatable() prepares a dma request.
+ * Returns 0 if all went okay, returns 1 otherwise.
+ */
+static int build_dmatable (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ struct buffer_head *bh = rq->bh;
+ unsigned long size, addr, *table = HWIF(drive)->dmatable;
+ unsigned int count = 0;
+
+ do {
+ /*
+ * Determine addr and size of next buffer area. We assume that
+ * individual virtual buffers are always composed linearly in
+ * physical memory. For example, we assume that any 8kB buffer
+ * is always composed of two adjacent physical 4kB pages rather
+ * than two possibly non-adjacent physical 4kB pages.
+ */
+ if (bh == NULL) { /* paging requests have (rq->bh == NULL) */
+ addr = virt_to_bus (rq->buffer);
+ size = rq->nr_sectors << 9;
+ } else {
+ /* group sequential buffers into one large buffer */
+ addr = virt_to_bus (bh->b_data);
+ size = bh->b_size;
+ while ((bh = bh->b_reqnext) != NULL) {
+ if ((addr + size) != virt_to_bus (bh->b_data))
+ break;
+ size += bh->b_size;
+ }
+ }
+
+ /*
+ * Fill in the dma table, without crossing any 64kB boundaries.
+ * We assume 16-bit alignment of all blocks.
+ */
+ while (size) {
+ if (++count >= PRD_ENTRIES) {
+ printk("%s: DMA table too small\n", drive->name);
+ return 1; /* revert to PIO for this request */
+ } else {
+ unsigned long bcount = 0x10000 - (addr & 0xffff);
+ if (bcount > size)
+ bcount = size;
+ *table++ = addr;
+ *table++ = bcount;
+ addr += bcount;
+ size -= bcount;
+ }
+ }
+ } while (bh != NULL);
+ if (count) {
+ *--table |= 0x80000000; /* set End-Of-Table (EOT) bit */
+ return 0;
+ }
+ printk("%s: empty DMA table?\n", drive->name);
+ return 1; /* let the PIO routines handle this weirdness */
+}
+
+/*
+ * triton_dmaproc() initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA. All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case
+ * the caller should revert to PIO for the current request.
+ */
+static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ const char **list;
+ unsigned long dma_base = HWIF(drive)->dma_base;
+
+ if (func == ide_dma_abort) {
+ outb(inb(dma_base)&~1, dma_base); /* stop DMA */
+ return 0;
+ }
+ if (func == ide_dma_check) {
+ struct hd_driveid *id = drive->id;
+ if (id && (id->capability & 1)) {
+ /* Enable DMA on any drive that supports mword2 DMA */
+ if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
+ drive->using_dma = 1;
+ return 0; /* DMA enabled */
+ }
+ /* Consult the list of known "good" drives */
+ list = good_dma_drives;
+ while (*list) {
+ if (!strcmp(*list++,id->model)) {
+ drive->using_dma = 1;
+ return 0; /* DMA enabled */
+ }
+ }
+ }
+ return 1; /* DMA not enabled */
+ }
+ if (build_dmatable (drive))
+ return 1;
+ outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */
+ outb((!func) << 3, dma_base); /* specify r/w */
+ outb(0x26, dma_base+2); /* clear status bits */
+ ide_set_handler (drive, &dma_intr); /* issue cmd to drive */
+ OUT_BYTE(func ? WIN_WRITEDMA : WIN_READDMA, IDE_COMMAND_REG);
+ outb(inb(dma_base)|1, dma_base); /* begin DMA */
+ return 0;
+}
+
+/*
+ * print_triton_drive_flags() displays the currently programmed options
+ * in the Triton chipset for a given drive.
+ *
+ * If fastDMA is "no", then slow ISA timings are used for DMA data xfers.
+ * If fastPIO is "no", then slow ISA timings are used for PIO data xfers.
+ * If IORDY is "no", then IORDY is assumed to always be asserted.
+ * If PreFetch is "no", then data pre-fetch/post are not used.
+ *
+ * When "fastPIO" and/or "fastDMA" are "yes", then faster PCI timings and
+ * back-to-back 16-bit data transfers are enabled, using the sample_CLKs
+ * and recovery_CLKs (PCI clock cycles) timing parameters for that interface.
+ */
+static void print_triton_drive_flags (unsigned int unit, byte flags)
+{
+ printk(" %s ", unit ? "slave :" : "master:");
+ printk( "fastDMA=%s", (flags&9) ? "on " : "off");
+ printk(" PreFetch=%s", (flags&4) ? "on " : "off");
+ printk(" IORDY=%s", (flags&2) ? "on " : "off");
+ printk(" fastPIO=%s\n", ((flags&9)==1) ? "on " : "off");
+}
+
+/*
+ * ide_init_triton() uses the PCI BIOS to scan for a Triton i82371FB chip,
+ * and prepares the IDE driver for DMA operation if one is found.
+ * This routine is called from ide.c during driver initialization.
+ */
+void ide_init_triton (ide_hwif_t hwifs[])
+{
+ int rc = 0, h;
+ unsigned short bmiba, pcicmd;
+ unsigned int timings;
+ unsigned char bus, fn;
+
+ if (pcibios_find_device (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371, 0, &bus, &fn))
+ goto quit;
+ ++fn; /* IDE is second function on this chip */
+
+ /*
+ * See if IDE and BM-DMA features are enabled:
+ */
+ if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd)))
+ goto quit;
+ if ((pcicmd & 5) != 5) {
+ if ((pcicmd & 1) == 0)
+ printk("ide: Triton IDE ports are not enabled\n");
+ else
+ printk("ide: Triton BM-DMA feature is not enabled\n");
+ goto quit;
+ }
+#if 0
+ (void) pcibios_write_config_word(bus, fn, 0x42, 0x8037); /* for my MC2112A */
+#endif
+ /*
+ * See if ide port(s) are enabled
+ */
+ if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings)))
+ goto quit;
+ if (!(timings & 0x80008000)) {
+ printk("ide: Triton IDE ports are not enabled\n");
+ goto quit;
+ }
+ printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn);
+
+ /*
+ * Get the bmiba base address
+ */
+ if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba)))
+ goto quit;
+ bmiba &= 0xfff0; /* extract port base address */
+
+ /*
+ * Save the dma_base port addr for each interface
+ */
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ ide_hwif_t *hwif = &hwifs[h];
+ unsigned short base, time;
+ if (hwif->io_base == 0x1f0 && (timings & 0x8000)) {
+ time = timings & 0xffff;
+ base = bmiba;
+ } else if (hwif->io_base == 0x170 && (timings & 0x80000000)) {
+ time = timings >> 16;
+ base = bmiba + 8;
+ } else
+ continue;
+ printk(" %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+5);
+ if (check_region(base, 6)) {
+ printk(" -- ERROR, PORTS ALREADY IN USE");
+ } else {
+ unsigned long *table;
+ request_region(base, 8, hwif->name);
+ hwif->dma_base = base;
+ table = ide_alloc(2 * PRD_ENTRIES * sizeof(long), 4096);
+ hwif->dmatable = table;
+ outl((unsigned long) table, base + 4);
+ hwif->dmaproc = &triton_dmaproc;
+ }
+ printk("\n %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
+ hwif->name, time, ((~time>>12)&3)+2, ((~time>>8)&3)+1);
+ print_triton_drive_flags (0, time & 0xf);
+ print_triton_drive_flags (1, (time >> 4) & 0xf);
+ }
+
+quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
+}
+
/* the BIOS manuals say there can be up to 4 lpt devices
* but I have not seen a board where the 4th address is listed
- * if you have different hardware change the table below
+ * if you have different hardware change the table below
* please let me know if you have different equipment
* if you have more than 3 printers, remember to increase LP_NO
*/
{ 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
{ 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
{ 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
-};
+};
#define LP_NO 3
/* Test if printer is ready (and optionally has no error conditions) */
((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : 1)
#define _LP_CAREFUL_READY(status) \
(status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
- (LP_PBUSY|LP_PSELECD|LP_PERRORP)
+ (LP_PBUSY|LP_PSELECD|LP_PERRORP)
-/*
+/*
* All my debugging code assumes that you debug with only one printer at
* a time. RWWH
* Debug info moved into stats area, so this is no longer true (Rob Janssen)
static inline int lp_char_polled(char lpchar, int minor)
{
int status, wait = 0;
- unsigned long count = 0;
+ unsigned long count = 0;
struct lp_stats *stats;
do {
/* must wait before taking strobe high, and after taking strobe
low, according spec. Some printers need it, others don't. */
while(wait != LP_WAIT(minor)) wait++;
- /* control port takes strobe high */
+ /* control port takes strobe high */
outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
while(wait) wait--;
- /* take strobe low */
+ /* take strobe low */
outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
/* update waittime statistics */
if (count > stats->maxwait) {
static inline int lp_char_interrupt(char lpchar, int minor)
{
int wait;
- unsigned long count = 0;
+ unsigned long count = 0;
unsigned char status;
struct lp_stats *stats;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
schedule();
} else
- /* not offline or out of paper. on fire? */
+ /* not offline or out of paper. on fire? */
if (!(status & LP_PERRORP)) {
printk(KERN_ERR "lp%d reported invalid error status (on fire, eh?)\n", minor);
if(LP_F(minor) & LP_ABORT)
have commandeered O_NONBLOCK, even though it is being used in
a non-standard manner. This is strictly a Linux hack, and
should most likely only ever be used by the tunelp application. */
- if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {
+ if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {
int status = LP_S(minor);
if (status & LP_POUTPA) {
printk(KERN_INFO "lp%d out of paper\n", minor);
printk("lp: unable to get major %d\n", LP_MAJOR);
#ifdef MODULE
return -EIO;
-#else
+#else
return kmem_start;
#endif
}
#ifdef MODULE
return 0;
-#else
+#else
return kmem_start;
#endif
}
#ifdef MODULE
void cleanup_module(void)
{
- int offset;
- if(MOD_IN_USE)
- printk("lp: busy - remove delayed\n");
- else {
- unregister_chrdev(LP_MAJOR,"lp");
- for (offset = 0; offset < LP_NO; offset++)
- if (LP_F(offset) & LP_EXIST)
- release_region(LP_B(offset),3);
+ int offset;
+
+ if(MOD_IN_USE) {
+ printk("lp: busy - remove delayed\n");
+ return;
+ }
+ unregister_chrdev(LP_MAJOR,"lp");
+ for (offset = 0; offset < LP_NO; offset++) {
+ int base, size;
+ base = LP_B(offset);
+ size = (base == 0x3bc)? 3 : 8;
+ if (LP_F(offset) & LP_EXIST)
+ release_region(LP_B(offset),size);
}
}
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
-#include <linux/major.h>
#include <linux/ioport.h>
#include <linux/mm.h>
depca.o: depca.c CONFIG
$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
-Space.o: ../../include/linux/autoconf.h
+Space.o: Space.c ../../include/linux/autoconf.h CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(OPTS) -c $<
net_init.o: ../../include/linux/autoconf.h
restore_flags(flags);
return;
}
- for (i = 0; i < MAX_ETH_CARDS; ++i)
+ }
+ for (i = 0; i < MAX_ETH_CARDS; ++i)
+ {
+ if (ethdev_index[i] == dev)
{
- if (ethdev_index[i] == dev)
- {
- ethdev_index[i] = NULL;
- break;
- }
+ ethdev_index[i] = NULL;
+ break;
}
}
restore_flags(flags);
/* If doing demand dial then divert the first frame to pppd. */
if (ppp->flags & SC_IP_DOWN) {
- if (ppp->flags & SC_IP_FLUSH == 0) {
+ if ((ppp->flags & SC_IP_FLUSH) == 0) {
if (ppp_us_queue (ppp, proto, p, len))
ppp->flags |= SC_IP_FLUSH;
}
BRIDGE( INTEL, INTEL_82434, "82434LX Mercury/Neptune", 0x00),
DEVICE( INTEL, INTEL_82430, "82430ZX Aries"),
DEVICE( INTEL, INTEL_82437, "82437 Triton"),
- DEVICE( INTEL, INTEL_82371, "82471 Triton"),
+ DEVICE( INTEL, INTEL_82371, "82371 Triton"),
DEVICE( INTEL, INTEL_82438, "82438"),
DEVICE( INTEL, INTEL_7116, "SAA7116"),
DEVICE( INTEL, INTEL_82865, "82865"),
case PCI_CLASS_NOT_DEFINED_VGA: return "VGA compatible device";
case PCI_CLASS_STORAGE_SCSI: return "SCSI storage controller";
- case PCI_CLASS_STORAGE_IDE: return "IDE controller";
+ case PCI_CLASS_STORAGE_IDE: return "IDE interface";
case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller";
case PCI_CLASS_STORAGE_IPI: return "IPI bus controller";
case PCI_CLASS_STORAGE_RAID: return "RAID bus controller";
$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c
aic7xxx_asm: aic7xxx_asm.c
- $(CC) $(CFLAGS) -o $@ aic7xxx_asm.c
+ $(HOSTCC) -o $@ aic7xxx_asm.c
aic7xxx.c: aic7xxx_seq.h
aic7xxx_seq.h: aic7xxx_asm aic7xxx.seq
* It is only initialized to !=0 if the scsi code is present
*/
extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start,
- off_t offset, int length, int inout);
+ off_t offset, int length, int inout);
extern int dispatch_scsi_info(int ino, char *buffer, char **start,
- off_t offset, int length, int inout);
+ off_t offset, int length, int inout);
/*
{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */
{"RODIME","RO3000S","2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1
- * for aha152x controller, which causes
- * SCSI code to reset bus.*/
+ * for aha152x controller, which causes
+ * SCSI code to reset bus.*/
{"SEAGATE", "ST296","921", BLIST_NOLUN}, /* Responds to all lun */
{"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN},
{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},
{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},
{"TANDBERG","TDC 3600","U07", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
{"TEAC","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1
- * for seagate controller, which causes
- * SCSI code to reset bus.*/
+ * for seagate controller, which causes
+ * SCSI code to reset bus.*/
{"TEXEL","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1
- * for seagate controller, which causes
- * SCSI code to reset bus.*/
+ * for seagate controller, which causes
+ * SCSI code to reset bus.*/
{"QUANTUM","LPS525S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */
{"QUANTUM","PD1225S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */
{"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
/*
* We need the for so our continue, etc. work fine.
- * We put this in a variable so that we can override
- * it during the scan if we detect a device *KNOWN*
- * to have multiple logical units.
+ * We put this in a variable so that we can override
+ * it during the scan if we detect a device *KNOWN*
+ * to have multiple logical units.
*/
- max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
- max_scsi_luns : shpnt->max_lun);
+ max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
+ max_scsi_luns : shpnt->max_lun);
for (lun = 0; lun < max_dev_lun; ++lun)
{
SDpnt->manufacturer = SCSI_MAN_NEC;
} else if (!strncmp(scsi_result+8,"TOSHIBA",7))
SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
- else if (!strncmp(scsi_result+8,"SONY",4))
- SDpnt->manufacturer = SCSI_MAN_SONY;
+ else if (!strncmp(scsi_result+8,"SONY",4))
+ SDpnt->manufacturer = SCSI_MAN_SONY;
else
SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
SDpnt->changed = 0;
SDpnt->access_count = 0;
SDpnt->busy = 0;
- SDpnt->has_cmdblocks = 0;
+ SDpnt->has_cmdblocks = 0;
/*
* Currently, all sequential devices are assumed to be
* tapes, all random devices disk, with the appropriate
#endif
}
- SDpnt->single_lun = 0;
+ SDpnt->single_lun = 0;
SDpnt->soft_reset =
(scsi_result[7] & 1) && ((scsi_result[3] &7) == 2);
SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
SDpnt->disconnect = 0;
- /*
- * Get any flags for this device.
- */
- bflags = get_device_flags(scsi_result);
+ /*
+ * Get any flags for this device.
+ */
+ bflags = get_device_flags(scsi_result);
/*
* change it here if it turns out that it isn't
* a TEXEL drive.
*/
- if( (bflags & BLIST_BORKEN) == 0 )
- {
+ if( (bflags & BLIST_BORKEN) == 0 )
+ {
SDpnt->borken = 0;
- }
+ }
/* These devices need this "key" to unlock the
* devices so we can use it
*/
- if( (bflags & BLIST_KEY) != 0 ) {
+ if( (bflags & BLIST_KEY) != 0 ) {
printk("Unlocked floptical drive.\n");
SDpnt->lockable = 0;
scsi_cmd[0] = MODE_SENSE;
*/
if(bflags & BLIST_NOLUN) break;
- /*
- * If we want to only allow I/O to one of the luns
- * attached to this device at a time, then we set this
- * flag.
- */
- if(bflags & BLIST_SINGLELUN)
- {
- SDpnt->single_lun = 1;
- }
-
- /*
- * If this device is known to support multiple units, override
- * the other settings, and scan all of them.
- */
- if(bflags & BLIST_FORCELUN)
- {
- /*
- * We probably want to make this a variable, but this
- * will do for now.
- */
- max_dev_lun = 8;
- }
+ /*
+ * If we want to only allow I/O to one of the luns
+ * attached to this device at a time, then we set this
+ * flag.
+ */
+ if(bflags & BLIST_SINGLELUN)
+ {
+ SDpnt->single_lun = 1;
+ }
+
+ /*
+ * If this device is known to support multiple units, override
+ * the other settings, and scan all of them.
+ */
+ if(bflags & BLIST_FORCELUN)
+ {
+ /*
+ * We probably want to make this a variable, but this
+ * will do for now.
+ */
+ max_dev_lun = 8;
+ }
/* Old drives like the MAXTOR XT-3280 say vers=0 */
}
} /* if result == DID_OK ends */
- /*
- * This might screw us up with multi-lun devices, but the user can
- * scan for them too.
- */
+ /*
+ * This might screw us up with multi-lun devices, but the user can
+ * scan for them too.
+ */
if(hardcoded == 1)
goto leave;
} /* for lun ends */
SCpnt = device->host->host_queue;
if (!device->single_lun) {
- while(SCpnt){
- if(SCpnt->target == device->id &&
- SCpnt->lun == device->lun) {
- if(SCpnt->request.dev < 0) break;
- }
- SCpnt = SCpnt->next;
- }
+ while(SCpnt){
+ if(SCpnt->target == device->id &&
+ SCpnt->lun == device->lun) {
+ if(SCpnt->request.dev < 0) break;
+ }
+ SCpnt = SCpnt->next;
+ }
} else {
- while(SCpnt){
- if(SCpnt->target == device->id) {
- if (SCpnt->lun == device->lun) {
- if(found == NULL
- && SCpnt->request.dev < 0)
- {
- found=SCpnt;
- }
- }
- if(SCpnt->request.dev >= 0) {
- /*
- * I think that we should really limit things to one
- * outstanding command per device - this is what tends to trip
- * up buggy firmware.
- */
- return NULL;
- }
- }
- SCpnt = SCpnt->next;
- }
- SCpnt = found;
+ while(SCpnt){
+ if(SCpnt->target == device->id) {
+ if (SCpnt->lun == device->lun) {
+ if(found == NULL
+ && SCpnt->request.dev < 0)
+ {
+ found=SCpnt;
+ }
+ }
+ if(SCpnt->request.dev >= 0) {
+ /*
+ * I think that we should really limit things to one
+ * outstanding command per device - this is what tends to trip
+ * up buggy firmware.
+ */
+ return NULL;
+ }
+ }
+ SCpnt = SCpnt->next;
+ }
+ SCpnt = found;
}
if (!SCpnt) return NULL;
if (intr_count && SCSI_BLOCK(host)) return NULL;
while (1==1){
- SCpnt = device->host->host_queue;
- if (!device->single_lun) {
- while(SCpnt){
- if(SCpnt->target == device->id &&
- SCpnt->lun == device->lun) {
- SCwait = SCpnt;
- if(SCpnt->request.dev < 0) break;
- }
- SCpnt = SCpnt->next;
- }
- } else {
- while(SCpnt){
- if(SCpnt->target == device->id) {
- if (SCpnt->lun == device->lun) {
- SCwait = SCpnt;
- if(found == NULL
- && SCpnt->request.dev < 0)
- {
- found=SCpnt;
- }
- }
- if(SCpnt->request.dev >= 0) {
- /*
- * I think that we should really limit things to one
- * outstanding command per device - this is what tends to trip
- * up buggy firmware.
- */
- found = NULL;
- break;
- }
- }
- SCpnt = SCpnt->next;
- }
- SCpnt = found;
- }
+ SCpnt = device->host->host_queue;
+ if (!device->single_lun) {
+ while(SCpnt){
+ if(SCpnt->target == device->id &&
+ SCpnt->lun == device->lun) {
+ SCwait = SCpnt;
+ if(SCpnt->request.dev < 0) break;
+ }
+ SCpnt = SCpnt->next;
+ }
+ } else {
+ while(SCpnt){
+ if(SCpnt->target == device->id) {
+ if (SCpnt->lun == device->lun) {
+ SCwait = SCpnt;
+ if(found == NULL
+ && SCpnt->request.dev < 0)
+ {
+ found=SCpnt;
+ }
+ }
+ if(SCpnt->request.dev >= 0) {
+ /*
+ * I think that we should really limit things to one
+ * outstanding command per device - this is what tends to trip
+ * up buggy firmware.
+ */
+ found = NULL;
+ break;
+ }
+ }
+ SCpnt = SCpnt->next;
+ }
+ SCpnt = found;
+ }
save_flags(flags);
cli();
scsi_init_memory_start += size;
}
}
- memset((void *) retval, 0, size);
+ if (retval)
+ memset((void *) retval, 0, size);
return (void *) retval;
}
dma_sectors = (dma_sectors + 15) & 0xfff0;
dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */
+
+ if (dma_sectors)
+ {
+ dma_malloc_freelist = (unsigned char *)
+ scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
+ memset(dma_malloc_freelist, 0, dma_sectors >> 3);
+
+ dma_malloc_pages = (unsigned char **)
+ scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
+ memset(dma_malloc_pages, 0, dma_sectors >> 1);
+
+ for(i=0; i< dma_sectors >> 3; i++)
+ dma_malloc_pages[i] = (unsigned char *)
+ scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
- dma_malloc_freelist = (unsigned char *)
- scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
- memset(dma_malloc_freelist, 0, dma_sectors >> 3);
-
- dma_malloc_pages = (unsigned char **)
- scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
- memset(dma_malloc_pages, 0, dma_sectors >> 1);
-
- for(i=0; i< dma_sectors >> 3; i++)
- dma_malloc_pages[i] = (unsigned char *)
- scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-
+ }
/* OK, now we finish the initialization by doing spin-up, read
* capacity, etc, etc
*/
HBA_ptr = scsi_hostlist;
if(inout == 0) {
- size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
- len += size;
- pos = begin + len;
- while (HBA_ptr) {
+ size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+ len += size;
+ pos = begin + len;
+ while (HBA_ptr) {
#if 0
- size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, HBA_ptr->hostt->procname);
- len += size;
- pos = begin + len;
+ size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, HBA_ptr->hostt->procname);
+ len += size;
+ pos = begin + len;
#endif
- scd = scsi_devices;
- while (scd) {
- if (scd->host == HBA_ptr) {
- proc_print_scsidevice(scd, buffer, &size, len);
- len += size;
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
- }
- scd = scd->next;
- }
+ scd = scsi_devices;
+ while (scd) {
+ if (scd->host == HBA_ptr) {
+ proc_print_scsidevice(scd, buffer, &size, len);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+ }
+ scd = scd->next;
+ }
HBA_ptr = HBA_ptr->next;
- }
-
+ }
+
stop_output:
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Start slop */
- if(len>length)
- len = length; /* Ending slop */
- return (len);
+ *start=buffer+(offset-begin); /* Start of wanted data */
+ len-=(offset-begin); /* Start slop */
+ if(len>length)
+ len = length; /* Ending slop */
+ return (len);
}
if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
*/
if( new_dma_sectors < dma_sectors )
new_dma_sectors = dma_sectors;
-
- new_dma_malloc_freelist = (unsigned char *)
- scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
- memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
-
- new_dma_malloc_pages = (unsigned char **)
- scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
- memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
-
+
+ if (new_dma_sectors)
+ {
+ new_dma_malloc_freelist = (unsigned char *)
+ scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
+ memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
+
+ new_dma_malloc_pages = (unsigned char **)
+ scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
+ memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
+ }
+
/*
* If we need more buffers, expand the list.
*/
*/
save_flags(flags);
cli();
- memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
- scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+ if (dma_malloc_freelist)
+ {
+ memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
+ scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+ }
dma_malloc_freelist = new_dma_malloc_freelist;
- memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
- scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
-
+ if (dma_malloc_pages)
+ {
+ memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
+ scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
+ }
+
dma_free_sectors += new_dma_sectors - dma_sectors;
dma_malloc_pages = new_dma_malloc_pages;
dma_sectors = new_dma_sectors;
scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
sdpnt->host->host_queue = SCpnt;
if (SCpnt) SCpnt->prev = NULL;
- sdpnt->has_cmdblocks = 0;
+ sdpnt->has_cmdblocks = 0;
}
/* Next free up the Scsi_Device structures for this host */
scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
}
}
- SDpnt->has_cmdblocks = 0;
+ SDpnt->has_cmdblocks = 0;
}
}
/*
struct hd_geometry *loc = (struct hd_geometry *) arg;
switch (cmd) {
- case HDIO_REQ: /* Return BIOS disk parameters */
+ case HDIO_GETGEO: /* Return BIOS disk parameters */
if (!loc) return -EINVAL;
error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
if (error)
prev = INB (io_Index_Addr (devc));
OUTB (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */
- if (prev & 0x40 == 0) /* Not in MCE mode */
+ if ((prev & 0x40) == 0) /* Not in MCE mode */
{
RESTORE_INTR (flags);
return;
{
DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
- if ((cmd >> 8) & 0xff == 'M' && num_mixers > 0) /* Mixer ioctl */
+ if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */
if ((dev & 0x0f) != SND_DEV_CTL)
{
int dtype = dev & 0x0f;
static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
struct inode * interpreter_inode, unsigned int *interp_load_addr)
{
- struct file * file;
+ struct file * file;
struct elf_phdr *elf_phdata = NULL;
struct elf_phdr *eppnt;
unsigned int len;
SYS(close)(elf_exec_fileno);
if(error < 0 && error > -1024) {
- kfree(elf_phdata);
+ kfree(elf_phdata);
return 0xffffffff;
}
retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
elf_ex.e_phentsize * elf_ex.e_phnum, 1);
if (retval < 0) {
- kfree (elf_phdata);
+ kfree (elf_phdata);
MOD_DEC_USE_COUNT;
return retval;
}
elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
if (elf_exec_fileno < 0) {
- kfree (elf_phdata);
+ kfree (elf_phdata);
MOD_DEC_USE_COUNT;
return elf_exec_fileno;
}
/* Some simple consistency checks for the interpreter */
if(elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
+ interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
if(retval < 0) {
kfree(elf_interpreter);
kfree(elf_phdata);
}
}
if (!bprm->p) {
- if(elf_interpreter) {
+ if(elf_interpreter) {
kfree(elf_interpreter);
}
- kfree (elf_phdata);
+ kfree (elf_phdata);
MOD_DEC_USE_COUNT;
return -E2BIG;
}
MAP_FIXED | MAP_PRIVATE, 0);
}
+ /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+ starts %edx contains a pointer to a function which might be
+ registered using `atexit'. This provides a mean for the
+ dynamic linker to call DT_FINI functions for shared libraries
+ that have been loaded before the code runs.
+
+ A value of 0 tells we have no such handler. */
+ regs->edx = 0;
+
start_thread(regs, elf_entry, bprm->p);
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
static int
load_elf_library(int fd){
- struct file * file;
+ struct file * file;
struct elfhdr elf_ex;
struct elf_phdr *elf_phdata = NULL;
struct inode * inode;
SYS(close)(fd);
if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
- kfree(elf_phdata);
+ kfree(elf_phdata);
MOD_DEC_USE_COUNT;
return error;
}
return address;
}
+#if 0
/*
* bwrite_page writes a page out to the buffer cache and/or the physical device.
* It's used for mmap writes (the same way bread_page() is used for mmap reads).
mark_buffer_dirty(bh[i], 0);
brelse(bh[i]);
} else
- memset((void *) address, 0, size);
+ memset((void *) address, 0, size); /* ???!?!! */
}
}
+#endif
/*
* Try to increase the number of buffers available: the size argument
char msdos_name[MSDOS_NAME];
int res;
- if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
- msdos_name,1)) < 0) return res;
+ res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, msdos_name,1);
+ if (res < 0)
+ return -ENOENT;
return msdos_scan(dir,msdos_name,bh,de,ino);
}
if (data->addr.sin_addr.s_addr == INADDR_ANY) { /* No address passed */
if (((struct sockaddr_in *)(&server->toaddr))->sin_addr.s_addr == INADDR_ANY) {
printk("NFS: Error passed unconnected socket and no address\n") ;
+ MOD_DEC_USE_COUNT;
return NULL ;
} else {
/* Need access to socket internals JSP */
#include <linux/config.h>
#include <linux/mm.h>
-static struct file_operations proc_netdir_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- proc_readdir, /* readdir */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-static struct inode_operations proc_netdir_inode_operations = {
- &proc_netdir_operations, /* default net directory file-ops */
- NULL, /* create */
- proc_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL /* permission */
-};
-
-struct proc_dir_entry proc_net = {
- PROC_NET, 3, "net",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_netdir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
static int proc_readnet(struct inode * inode, struct file * file,
static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
+/*
+ * These are the generic /proc directory operations. They
+ * use the in-memory "struct proc_dir_entry" tree to parse
+ * the /proc directory.
+ *
+ * NOTE! The /proc/scsi directory currently does not correctly
+ * build up the proc_dir_entry tree, and will show up empty.
+ */
+static struct file_operations proc_dir_operations = {
+ NULL, /* lseek - default */
+ NULL, /* read - bad */
+ NULL, /* write - bad */
+ proc_readdir, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+static struct inode_operations proc_dir_inode_operations = {
+ &proc_dir_operations, /* default net directory file-ops */
+ NULL, /* create */
+ proc_lookup, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+/*
+ * The root /proc directory is special, as it has the
+ * <pid> directories. Thus we don't use the generic
+ * directory handling functions for that..
+ */
static struct file_operations proc_root_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
};
/*
- * proc directories can do almost nothing..
+ * proc root can do almost nothing..
*/
static struct inode_operations proc_root_inode_operations = {
&proc_root_operations, /* default base directory file-ops */
*/
struct proc_dir_entry proc_root = {
PROC_ROOT_INO, 5, "/proc",
- S_IFDIR | S_IRUGO | S_IXUGO, 3, 0, 0,
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_root_inode_operations,
NULL, NULL,
NULL,
&proc_root, NULL
};
+struct proc_dir_entry proc_net = {
+ PROC_NET, 3, "net",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+ 0, &proc_dir_inode_operations,
+ NULL, NULL,
+ NULL,
+ NULL, NULL
+};
+
+struct proc_dir_entry proc_scsi = {
+ PROC_SCSI, 4, "scsi",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+ 0, &proc_dir_inode_operations,
+ NULL, NULL,
+ NULL,
+ &proc_root, NULL
+};
+
int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{
dp->next = dir->subdir;
char * buf, int count);
static int proc_writescsi(struct inode * inode, struct file * file,
const char * buf, int count);
-static int proc_readscsidir(struct inode *, struct file *,
- void *, filldir_t filldir);
static int proc_lookupscsi(struct inode *,const char *,int,struct inode **);
static int proc_scsilseek(struct inode *, struct file *, off_t, int);
proc_scsilseek, /* lseek */
proc_readscsi, /* read */
proc_writescsi, /* write */
- proc_readscsidir, /* readdir */
+ NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
NULL /* permission */
};
-struct proc_dir_entry proc_scsi = {
- PROC_SCSI, 4, "scsi",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_scsi_inode_operations,
- NULL, NULL,
- NULL,
- &proc_root, NULL
-};
-
struct proc_dir_entry scsi_dir[PROC_SCSI_FILE - PROC_SCSI_SCSI + 3];
struct proc_dir_entry scsi_hba_dir[(PROC_SCSI_LAST - PROC_SCSI_FILE) * 4];
return(-ENOENT);
}
-static int proc_readscsidir(struct inode * inode, struct file * filp,
- void * dirent, filldir_t filldir)
-{
- struct proc_dir_entry * de;
- uint index, num;
-
- num = 0;
-
- if (!inode || !S_ISDIR(inode->i_mode))
- return(-EBADF);
-
- index = count_dir_entries(inode->i_ino, &num);
-
- while (((unsigned) filp->f_pos + index) < index + num) {
- if (dispatch_scsi_info_ptr) {
- if (inode->i_ino <= PROC_SCSI_SCSI)
- de = scsi_dir + filp->f_pos;
- else
- de = scsi_hba_dir + filp->f_pos + index;
- }
- else {
- de = scsi_dir2 + filp->f_pos;
- }
- if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino)<0)
- break;
- filp->f_pos++;
- }
- return(0);
-}
-
int get_not_present_info(char *buffer, char **start, off_t offset, int length)
{
int len, pos, begin;
smbfs is a filesystem which understands the SMB protocol. This is the
protocol Windows for Workgroups, Windows NT or Lan Manager use to talk
-to each other. It was inspired by samba, the program by Andrew
-Tridgell that turns any unix site into a file server for DOS or
+to each other. smbfs was inspired by samba, the program written by
+Andrew Tridgell that turns any unix host into a file server for DOS or
Windows clients. See ftp://nimbus.anu.edu.au/pub/tridge/samba/ for
this interesting program suite and lots of more information on SMB and
NetBIOS over TCP/IP. There you also find explanation for conceps like
static struct smb_dirent* c_entry = NULL;
static int
-smb_readdir1(struct inode *inode, const struct file *filp,
- struct smb_dirent *ret,ino_t *ino)
+smb_readdir(struct inode *inode, struct file *filp,
+ void *dirent, filldir_t filldir)
{
int result, i = 0;
+ int index = 0;
struct smb_dirent *entry = NULL;
struct smb_server *server = SMB_SERVER(inode);
if (filp->f_pos == c_entry[i].f_pos) {
entry = &c_entry[i];
c_last_returned_index = i;
+ index = i;
break;
}
}
c_size = result;
entry = c_entry;
c_last_returned_index = 0;
+ index = 0;
for (i = 0; i < c_size; i++) {
switch (server->case_handling)
}
}
}
-
- if (entry) {
+
+ if (entry == NULL) {
+ /* Nothing found, even from a smb call */
+ return 0;
+ }
+
+ while (index < c_size) {
/* We found it. For getwd(), we have to return the
correct inode in d_ino if the inode is currently in
use. Otherwise the inode number does not
- matter. */
+ matter. (You can argue a lot about this..) */
- int path_len;
+ int path_len;
+ int len;
struct smb_inode_info *ino_info;
char complete_path[SMB_MAXPATHLEN];
-
-
- i = strlen(entry->path);
- if ((result = get_pname_static(inode, entry->path, i,
+ len = strlen(entry->path);
+ if ((result = get_pname_static(inode, entry->path, len,
complete_path,
&path_len)) < 0)
return result;
DDPRINTK("smb_readdir: entry->path = %s\n", entry->path);
DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos);
- *ino = (ino_t)ino_info; /* use the pointer as the
- inode - dangerous if we have
- 64 bit pointers! FIXME */
-
- *ret = *entry;
- return 1;
- }
-
- return 0;
-}
-
-static int
-smb_readdir(struct inode *inode, struct file *filp,
- void *dirent, filldir_t filldir)
-{
- struct smb_dirent d;
- ino_t ino;
+ if (filldir(dirent, entry->path, len,
+ entry->f_pos, (ino_t)ino_info) < 0) {
+ break;
+ }
- while (smb_readdir1(inode,filp,&d,&ino) == 1) {
- if (filldir(dirent,d.path,strlen(d.path)+1,
- filp->f_pos,ino) < 0) {
- return 0;
- }
- filp->f_pos++;
+ if ( (inode->i_ino != c_ino)
+ || (entry->f_pos != filp->f_pos)) {
+ /* Someone has destroyed the cache while we slept
+ in filldir */
+ break;
+ }
+ filp->f_pos += 1;
+ index += 1;
+ entry += 1;
}
return 0;
}
found_in_cache = 0;
if (dir->i_ino == c_ino) {
- int first = c_last_returned_index - 1;
+ int first = c_last_returned_index;
int i;
- if (first < 0) {
- first = c_size - 1;
- }
-
i = first;
do {
DDPRINTK("smb_lookup: trying index: %d, name: %s\n",
break;
}
i = (i + 1) % c_size;
-
+ DDPRINTK("smb_lookup: index %d, name %s failed\n",
+ i, c_entry[i].path);
} while (i != first);
}
res = smb_proc_mv(SMB_SERVER(old_dir), old_path, old_len,
new_path, new_len);
+ if (res == -EEXIST) {
+ int res1;
+ res1 = smb_proc_unlink(SMB_SERVER(old_dir), new_path, new_len);
+ if (res1 == 0) {
+ res = smb_proc_mv(SMB_SERVER(old_dir), old_path,
+ old_len, new_path, new_len);
+ }
+ }
+
if (res == 0) {
smb_invalid_dir_cache(old_dir->i_ino);
smb_invalid_dir_cache(new_dir->i_ino);
- }
+ }
finished:
iput(old_dir);
/* First read in as much as possible for each bufsize. */
while (already_read < count) {
- to_read = min(bufsize, count - already_read);
+ result = 0;
+ to_read = 0;
+
+ if ((SMB_SERVER(inode)->blkmode & 1) != 0) {
+ to_read = min(65535, count - already_read);
+ DPRINTK("smb_file_read: Raw %d bytes\n", to_read);
+ result = smb_proc_read_raw(SMB_SERVER(inode),
+ SMB_FINFO(inode),
+ pos, to_read, buf);
+ DPRINTK("smb_file_read: returned %d\n", result);
+ }
+
+ if (result <= 0) {
+ to_read = min(bufsize, count - already_read);
+ result = smb_proc_read(SMB_SERVER(inode),
+ SMB_FINFO(inode),
+ pos, to_read, buf, 1);
+ }
- result = smb_proc_read(SMB_SERVER(inode), SMB_FINFO(inode),
- pos, to_read, buf, 1);
if (result < 0)
return result;
pos += result;
already_written = 0;
+ DPRINTK("smb_write_file: blkmode = %d, blkmode & 2 = %d\n",
+ SMB_SERVER(inode)->blkmode,
+ SMB_SERVER(inode)->blkmode & 2);
+
while (already_written < count) {
- to_write = min(bufsize, count - already_written);
-
- result = smb_proc_write(SMB_SERVER(inode), SMB_FINFO(inode),
- pos, to_write, buf);
+ result = 0;
+ to_write = 0;
+
+ if ((SMB_SERVER(inode)->blkmode & 2) != 0) {
+ to_write = min(65535, count - already_written);
+ DPRINTK("smb_file_write: Raw %d bytes\n", to_write);
+ result = smb_proc_write_raw(SMB_SERVER(inode),
+ SMB_FINFO(inode),
+ pos, to_write, buf);
+ DPRINTK("smb_file_write: returned %d\n", result);
+ }
+
+ if (result <= 0) {
+ to_write = min(bufsize, count - already_written);
+ result = smb_proc_write(SMB_SERVER(inode),
+ SMB_FINFO(inode),
+ pos, to_write, buf);
+ }
if (result < 0)
return result;
if ((error = inode_change_ok(inode, attr)) < 0)
return error;
- if (!S_ISREG(inode->i_mode))
- return -EPERM;
+ if (((attr->ia_valid & ATTR_UID) &&
+ (attr->ia_uid != SMB_SERVER(inode)->m.uid)))
+ return -EPERM;
- if ((attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) != 0) {
+ if (((attr->ia_valid & ATTR_GID) &&
+ (attr->ia_uid != SMB_SERVER(inode)->m.gid)))
return -EPERM;
- }
-
+
+ if (((attr->ia_valid & ATTR_MODE) &&
+ (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
+ return -EPERM;
+
if ((attr->ia_valid & ATTR_SIZE) != 0) {
if ((error = smb_make_open(inode, O_WRONLY)) < 0)
return &p[2];
}
-static byte *
-smb_decode_dword(byte *p, dword *data)
-{
-#if (ARCH == i386)
- *data = *((dword *)p);
-#else
- *data = (dword)p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
-#endif
- return &p[4];
-}
-
-static byte *
+byte *
smb_encode_smb_length(byte *p, dword len)
{
p[0] = p[1] = 0;
case ERRlock: return EDEADLOCK;
case ERRfilexists: return EEXIST;
case 87: return 0; /* Unknown error!! */
+ /* This next error seems to occur on an mv when
+ * the destination exists */
+ case 183: return EEXIST;
default: return EIO;
}
else if (errcls == ERRSRV)
return data_len;
}
+/* count must be <= 65535. No error number is returned. A result of 0
+ indicates an error, which has to be investigated by a normal read
+ call. */
+int
+smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo,
+ off_t offset, long count, char *data)
+{
+ char *buf = server->packet;
+ int result;
+
+ if ((count <= 0) || (count > 65535)) {
+ return -EINVAL;
+ }
+
+ smb_setup_header_exclusive(server, SMBreadbraw, 8, 0);
+
+ WSET(buf, smb_vwv0, finfo->fileid);
+ DSET(buf, smb_vwv1, offset);
+ WSET(buf, smb_vwv3, count);
+ WSET(buf, smb_vwv4, 0);
+ DSET(buf, smb_vwv5, 0);
+
+ result = smb_request_read_raw(server, data, count);
+ smb_unlock_server(server);
+ return result;
+}
+
int
smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
off_t offset, int count, const char *data)
return res;
}
+/* count must be <= 65535 */
+int
+smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo,
+ off_t offset, long count, const char *data)
+{
+ char *buf = server->packet;
+ int result;
+
+ if ((count <= 0) || (count > 65535)) {
+ return -EINVAL;
+ }
+
+ smb_setup_header_exclusive(server, SMBwritebraw, 11, 0);
+
+ WSET(buf, smb_vwv0, finfo->fileid);
+ WSET(buf, smb_vwv1, count);
+ WSET(buf, smb_vwv2, 0); /* reserved */
+ DSET(buf, smb_vwv3, offset);
+ DSET(buf, smb_vwv5, 0); /* timeout */
+ WSET(buf, smb_vwv7, 1); /* send final result response */
+ DSET(buf, smb_vwv8, 0); /* reserved */
+ WSET(buf, smb_vwv10, 0); /* no data in this buf */
+ WSET(buf, smb_vwv11, 0); /* no data in this buf */
+
+ result = smb_request_ok(server, SMBwritebraw, 1, 0);
+
+ DPRINTK("smb_proc_write_raw: first request returned %d\n", result);
+
+ if (result < 0) {
+ smb_unlock_server(server);
+ return result;
+ }
+
+ result = smb_request_write_raw(server, data, count);
+
+ DPRINTK("smb_proc_write_raw: raw request returned %d\n", result);
+
+ if (result > 0) {
+ /* We have to do the checks of smb_request_ok here as well */
+ if (smb_valid_packet(server->packet) != 0) {
+ DPRINTK("not a valid packet!\n");
+ result = -EIO;
+ } else if (server->rcls != 0) {
+ result = -smb_errno(server->rcls, server->err);
+ } else if (smb_verify(server->packet, SMBwritec,1,0) != 0) {
+ DPRINTK("smb_verify failed\n");
+ result = -EIO;
+ }
+ }
+
+ smb_unlock_server(server);
+ return result;
+}
+
+
/* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */
static int
server->m.password);
DPRINTK("smb_proc_connect: usernam = %s\n",
server->m.username);
+ DPRINTK("smb_proc_connect: blkmode = %d\n",
+ WVAL(server->packet, smb_vwv5));
- p = smb_decode_word(p, &(server->maxxmt));
- p = smb_decode_word(p, &(server->maxmux));
- p = smb_decode_word(p, &(server->maxvcs));
- p = smb_decode_word(p, &(server->blkmode));
- p = smb_decode_dword(p, &(server->sesskey));
+ server->maxxmt = WVAL(server->packet, smb_vwv2);
+ server->maxmux = WVAL(server->packet, smb_vwv3);
+ server->maxvcs = WVAL(server->packet, smb_vwv4);
+ server->blkmode= WVAL(server->packet, smb_vwv5);
+ server->sesskey= DVAL(server->packet, smb_vwv6);
smb_setup_header(server, SMBsesssetupX, 10,
2 + userlen + passlen);
}
smb_decode_word(server->packet+32, &(server->server_uid));
}
+ else
+
+ {
+ server->maxxmt = 0;
+ server->maxmux = 0;
+ server->maxvcs = 0;
+ server->blkmode = 0;
+ server->sesskey = 0;
+ }
/* Fine! We have a connection, send a tcon message. */
}
/*
- * smb_receive
- * fs points to the correct segment, server != NULL, sock!=NULL
+ * smb_receive_raw
+ * fs points to the correct segment, sock != NULL, target != NULL
+ * The smb header is only stored if want_header != 0.
*/
static int
-smb_receive(struct smb_server *server, struct socket *sock)
+smb_receive_raw(struct socket *sock, unsigned char *target,
+ int max_raw_length, int want_header)
{
int len, result;
+ int already_read;
unsigned char peek_buf[4];
+ unsigned short fs; /* We fool the kernel to believe
+ we call from user space. */
+
re_recv:
+ fs = get_fs();
+ set_fs(get_ds());
result = sock->ops->recvfrom(sock, (void *)peek_buf, 4, 0,
- MSG_PEEK, NULL, NULL);
+ 0, NULL, NULL);
+ set_fs(fs);
if (result < 0) {
- DPRINTK("smb_receive: recv error = %d\n", -result);
+ DPRINTK("smb_receive_raw: recv error = %d\n", -result);
return result;
}
- if (result == 0) {
- DPRINTK("smb_receive: got 0 bytes\n");
+ if (result < 4) {
+ DPRINTK("smb_receive_raw: got less than 4 bytes\n");
return -EIO;
}
break;
case 0x85:
- DPRINTK("smb_receive: Got SESSION KEEP ALIVE\n");
- sock->ops->recvfrom(sock, (void *)peek_buf, 4, 1,
- 0, NULL, NULL);
+ DPRINTK("smb_receive_raw: Got SESSION KEEP ALIVE\n");
goto re_recv;
default:
- printk("smb_receive: Invalid packet\n");
+ printk("smb_receive_raw: Invalid packet\n");
return -EIO;
}
- /* Length not including first four bytes. */
- len = smb_len(peek_buf) + 4;
- if (len > server->max_xmit) {
- printk("smb_receive: Received length (%d) > max_xmit (%d)!\n",
- len, server->max_xmit);
+ /* The length in the RFC NB header is the raw data length */
+ len = smb_len(peek_buf);
+ if (len > max_raw_length) {
+ printk("smb_receive_raw: Received length (%d) > max_xmit (%d)!\n",
+ len, max_raw_length);
return -EIO;
}
- else
- {
- int already_read = 0;
- while (already_read < len) {
+ if (want_header != 0) {
+ memcpy_tofs(target, peek_buf, 4);
+ target += 4;
+ }
+
+ already_read = 0;
+
+ while (already_read < len) {
- result = sock->ops->
- recvfrom(sock,
- (void *)(server->packet+already_read),
- len - already_read, 0, 0,
- NULL, NULL);
+ result = sock->ops->
+ recvfrom(sock,
+ (void *)(target+already_read),
+ len - already_read, 0, 0,
+ NULL, NULL);
- if (result < 0) {
- printk("SMB: notice message: error = %d\n",
- -result);
- return result;
- }
-
- already_read += result;
+ if (result < 0) {
+ printk("smb_receive_raw: recvfrom error = %d\n",
+ -result);
+ return result;
}
- result = already_read;
+
+ already_read += result;
+ }
+ return already_read;
+}
+
+/*
+ * smb_receive
+ * fs points to the correct segment, server != NULL, sock!=NULL
+ */
+static int
+smb_receive(struct smb_server *server, struct socket *sock)
+{
+ int result;
+
+ result = smb_receive_raw(sock, server->packet,
+ server->max_xmit - 4, /* max_xmit in server
+ includes NB header */
+ 1); /* We want the header */
+
+ if (result < 0) {
+ printk("smb_receive: receive error: %d\n", result);
+ return result;
}
server->rcls = *((unsigned char *)(server->packet+9));
server->err = *((unsigned short *)(server->packet+11));
if (server->rcls != 0) {
- DPRINTK("smb_response: rcls=%d, err=%d\n",
+ DPRINTK("smb_receive: rcls=%d, err=%d\n",
server->rcls, server->err);
}
if (server->state != CONN_VALID)
return -EIO;
-#if 0
- while (server->lock)
- sleep_on(&server->wait);
- server->lock = 1;
-#endif
-
if ((result = smb_dont_catch_keepalive(server)) != 0) {
server->state = CONN_INVALID;
smb_invalidate_all_inodes(server);
result = result2;
}
-#if 0
- server->lock = 0;
- wake_up(&server->wait);
-#endif
-
if (result < 0) {
server->state = CONN_INVALID;
smb_invalidate_all_inodes(server);
if (server->state != CONN_VALID)
return -EIO;
-#if 0
- while (server->lock)
- sleep_on(&server->wait);
- server->lock = 1;
-#endif
-
if ((result = smb_dont_catch_keepalive(server)) != 0) {
server->state = CONN_INVALID;
smb_invalidate_all_inodes(server);
len = smb_len(buffer) + 4;
- DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
-
old_mask = current->blocked;
current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
fs = get_fs();
set_fs(get_ds());
+ DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
+
result = sock->ops->send(sock, (void *)buffer, len, 0, 0);
if (result < 0) {
printk("smb_trans2_request: send error = %d\n", result);
result = result2;
}
-#if 0
- server->lock = 0;
- wake_up(&server->wait);
-#endif
-
if (result < 0) {
server->state = CONN_INVALID;
smb_invalidate_all_inodes(server);
return result;
}
+/* target must be in user space */
+int
+smb_request_read_raw(struct smb_server *server,
+ unsigned char *target, int max_len)
+{
+ unsigned long old_mask;
+ int len, result, result2;
+ unsigned short fs; /* We fool the kernel to believe
+ we call from user space. */
+
+ struct socket *sock = server_sock(server);
+ unsigned char *buffer = (server == NULL) ? NULL : server->packet;
+
+ if ((sock == NULL) || (buffer == NULL)) {
+ printk("smb_request_read_raw: Bad server!\n");
+ return -EBADF;
+ }
+
+ if (server->state != CONN_VALID)
+ return -EIO;
+
+ if ((result = smb_dont_catch_keepalive(server)) != 0) {
+ server->state = CONN_INVALID;
+ smb_invalidate_all_inodes(server);
+ return result;
+ }
+
+ len = smb_len(buffer) + 4;
+
+ old_mask = current->blocked;
+ current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
+ fs = get_fs();
+ set_fs(get_ds());
+
+ DPRINTK("smb_request_read_raw: len = %d cmd = 0x%X\n",
+ len, buffer[8]);
+ DPRINTK("smb_request_read_raw: target=%X, max_len=%d\n",
+ (unsigned int)target, max_len);
+ DPRINTK("smb_request_read_raw: buffer=%X, sock=%X\n",
+ (unsigned int)buffer, (unsigned int)sock);
+
+ result = sock->ops->send(sock, (void *)buffer, len, 0, 0);
+
+ DPRINTK("smb_request_read_raw: send returned %d\n", result);
+
+ set_fs(fs); /* We recv into user space */
+
+ if (result < 0) {
+ printk("smb_request_read_raw: send error = %d\n", result);
+ }
+ else {
+ result = smb_receive_raw(sock, target, max_len, 0);
+ }
+
+ /* read/write errors are handled by errno */
+ current->signal &= ~_S(SIGPIPE);
+ current->blocked = old_mask;
+
+ if ((result2 = smb_catch_keepalive(server)) < 0) {
+ result = result2;
+ }
+
+ if (result < 0) {
+ server->state = CONN_INVALID;
+ smb_invalidate_all_inodes(server);
+ }
+
+ DPRINTK("smb_request_read_raw: result = %d\n", result);
+
+ return result;
+}
+
+/* Source must be in user space. smb_request_write_raw assumes that
+ * the request SMBwriteBraw has been completed successfully, so that
+ * we can send the raw data now. */
+int
+smb_request_write_raw(struct smb_server *server,
+ unsigned const char *source, int length)
+{
+ unsigned long old_mask;
+ int result, result2;
+ unsigned short fs; /* We fool the kernel to believe
+ we call from user space. */
+ byte nb_header[4];
+
+ struct socket *sock = server_sock(server);
+ unsigned char *buffer = (server == NULL) ? NULL : server->packet;
+
+ if ((sock == NULL) || (buffer == NULL)) {
+ printk("smb_request_write_raw: Bad server!\n");
+ return -EBADF;
+ }
+
+ if (server->state != CONN_VALID)
+ return -EIO;
+
+ if ((result = smb_dont_catch_keepalive(server)) != 0) {
+ server->state = CONN_INVALID;
+ smb_invalidate_all_inodes(server);
+ return result;
+ }
+
+ old_mask = current->blocked;
+ current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
+ fs = get_fs();
+ set_fs(get_ds());
+
+ smb_encode_smb_length(nb_header, length);
+
+ result = sock->ops->send(sock, (void *)nb_header, 4, 0, 0);
+
+ if (result == 4) {
+ set_fs(fs); /* source is in user-land */
+ result = sock->ops->send(sock, (void *)source, length, 0, 0);
+ set_fs(get_ds());
+ } else {
+ result = -EIO;
+ }
+
+ DPRINTK("smb_request_write_raw: send returned %d\n", result);
+
+ if (result == length) {
+ result = smb_receive(server, sock);
+ } else {
+ result = -EIO;
+ }
+
+ /* read/write errors are handled by errno */
+ current->signal &= ~_S(SIGPIPE);
+ current->blocked = old_mask;
+ set_fs(fs);
+
+ if ((result2 = smb_catch_keepalive(server)) < 0) {
+ result = result2;
+ }
+
+ if (result < 0) {
+ server->state = CONN_INVALID;
+ smb_invalidate_all_inodes(server);
+ }
+
+ if (result > 0) {
+ result = length;
+ }
+
+ DPRINTK("smb_request_write_raw: result = %d\n", result);
+
+ return result;
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
return (s);
}
+/* Added by Gertjan van Wingerde to make minix and sysv module work */
+#define __HAVE_ARCH_STRNLEN
+extern inline size_t strnlen(const char * s, size_t count)
+{
+register int __res;
+__asm__ __volatile__(
+ "movl %1,%0\n\t"
+ "jmp 2f\n"
+ "1:\tcmpb $0,(%0)\n\t"
+ "je 3f\n\t"
+ "incl %0\n"
+ "2:\tdecl %2\n\t"
+ "cmpl $-1,%2\n\t"
+ "jne 1b\n"
+ "3:\tsubl %1,%0"
+ :"=a" (__res):"c" (s),"d" (count));
+return __res;
+}
+/* end of additional stuff */
/*
* This looks horribly ugly, but the compiler can optimize it totally,
#define __NR_getdents 141
#define __NR__newselect 142
#define __NR_flock 143
+#define __NR_msync 144
/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
#define _syscall0(type,name) \
#define WIN_DOORLOCK 0xde /* lock door on removeable drives */
#define WIN_DOORUNLOCK 0xdf /* unlock door on removeable drives */
-#define WIN_PIDENTIFY 0xA1 /* identify ATA-PI device */
-#define WIN_MULTREAD 0xC4 /* read multiple sectors */
-#define WIN_MULTWRITE 0xC5 /* write multiple sectors */
-#define WIN_SETMULT 0xC6 /* enable read multiple */
+#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode */
+#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
+#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */
-#define WIN_SETFEATURES 0xEF /* set special drive features */
+#define WIN_SETFEATURES 0xEF /* set special drive features */
+#define WIN_READDMA 0xc8 /* read sectors using DMA transfers */
+#define WIN_WRITEDMA 0xca /* write sectors using DMA transfers */
+
+/* Additional drive command codes used by ATAPI devices. */
+#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */
+#define WIN_SRST 0x08 /* ATAPI soft reset command */
+#define WIN_PACKETCMD 0xa0 /* Send a packet command. */
/* Bits for HD_ERROR */
#define MARK_ERR 0x01 /* Bad address mark */
/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x30n/0x31n */
#define HDIO_GETGEO 0x301 /* get device geometry */
-#define HDIO_REQ HDIO_GETGEO /* obsolete, use HDIO_GETGEO */
#define HDIO_GET_UNMASKINTR 0x302 /* get current unmask setting */
#define HDIO_GET_MULTCOUNT 0x304 /* get current IDE blockmode setting */
#define HDIO_GET_IDENTITY 0x307 /* get IDE identification info */
#define HDIO_GET_KEEPSETTINGS 0x308 /* get keep-settings-on-reset flag */
#define HDIO_GET_CHIPSET 0x309 /* get current interface type setting */
-#define HDIO_GET_NOWERR 0x30a /* get ignore-write-error flag */
+#define HDIO_GET_NOWERR 0x30a /* get ignore-write-error flag */
+#define HDIO_GET_DMA 0x30b /* get use-dma flag */
#define HDIO_DRIVE_CMD 0x31f /* execute a special drive command */
/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x32n/0x33n */
#define HDIO_SET_UNMASKINTR 0x322 /* permit other irqs during I/O */
#define HDIO_SET_KEEPSETTINGS 0x323 /* keep ioctl settings on reset */
#define HDIO_SET_CHIPSET 0x324 /* optimise driver for interface type */
-#define HDIO_SET_NOWERR 0x325 /* set ignore-write-error flag */
+#define HDIO_SET_NOWERR 0x325 /* set ignore-write-error flag */
+#define HDIO_SET_DMA 0x326 /* set use-dma flag */
/* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
struct hd_driveid {
#define ARPHRD_AX25 3 /* AX.25 Level 2 */
#define ARPHRD_PRONET 4 /* PROnet token ring */
#define ARPHRD_CHAOS 5 /* Chaosnet */
-#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet- huh? */
+#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */
#define ARPHRD_ARCNET 7 /* ARCnet */
#define ARPHRD_APPLETLK 8 /* APPLEtalk */
/* Dummy types for non ARP hardware */
#define ARPHRD_ADAPT 264
#define ARPHRD_PPP 512
#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
+#define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */
/* ARP protocol opcodes. */
#define ARPOP_REQUEST 1 /* ARP request */
#define ETH_P_ATALK 0x809B /* Appletalk DDP */
#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
#define ETH_P_IPX 0x8137 /* IPX over DIX */
+#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
#endif
+/*
+ * IPv6 definitions as we start to include them. This is just
+ * a beginning dont get excited 8)
+ */
+
+struct in_addr6
+{
+ unsigned char s6_addr[16];
+};
+
+struct sockaddr_in6
+{
+ unsigned short sin6_family;
+ unsigned short sin6_port;
+ unsigned long sin6_flowinfo;
+ struct in_addr6 sin6_addr;
+};
+
+
#endif /* _LINUX_IN_H */
void (*close)(struct vm_area_struct * area);
void (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
void (*protect)(struct vm_area_struct *area, unsigned long, size_t, unsigned int newprot);
- void (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags);
+ int (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags);
void (*advise)(struct vm_area_struct *area, unsigned long, size_t, unsigned int advise);
unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address,
unsigned long page, int write_access);
unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
unsigned long page);
- void (*swapout)(struct vm_area_struct *, unsigned long, pte_t *);
+ int (*swapout)(struct vm_area_struct *, unsigned long, pte_t *);
pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
};
extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
extern int datagram_select(struct sock *sk, int sel_type, select_table *wait);
extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
+extern void skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size);
extern void skb_free_datagram(struct sk_buff *skb);
#endif /* __KERNEL__ */
/* linux/fs/smbfs/proc.c */
dword smb_len(unsigned char *packet);
+byte *smb_encode_smb_length(byte *p, dword len);
int smb_proc_open(struct smb_server *server, const char *pathname,
int len, struct smb_dirent *entry);
int smb_proc_close(struct smb_server *server, struct smb_dirent *finfo);
int smb_proc_read(struct smb_server *server, struct smb_dirent *finfo,
off_t offset, long count, char *data, int fs);
+int smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo,
+ off_t offset, long count, char *data);
int smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
off_t offset, int count, const char *data);
+int smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo,
+ off_t offset, long count, const char *data);
int smb_proc_create(struct smb_server *server, const char *path,
int len, struct smb_dirent *entry);
int smb_proc_mknew(struct smb_server *server, const char *path, int len,
int smb_release(struct smb_server *server);
int smb_connect(struct smb_server *server);
int smb_request(struct smb_server *server);
+int smb_request_read_raw(struct smb_server *server,
+ unsigned char *target, int max_len);
+int smb_request_write_raw(struct smb_server *server,
+ unsigned const char *source, int length);
int smb_catch_keepalive(struct smb_server *server);
int smb_dont_catch_keepalive(struct smb_server *server);
int smb_trans2_request(struct smb_server *server,
#define AF_BRIDGE 7 /* Multiprotocol bridge */
#define AF_AAL5 8 /* Reserved for Werner's ATM */
#define AF_X25 9 /* Reserved for X.25 project */
+#define AF_INET6 10 /* IP version 6 */
#define AF_MAX 12 /* For now.. */
/* Protocol families, same as address families. */
#define PF_BRIDGE AF_BRIDGE
#define PF_AAL5 AF_AAL5
#define PF_X25 AF_X25
+#define PF_INET6 AF_INET6
#define PF_MAX AF_MAX
extern struct nr_parms_struct nr_default;
extern int nr_rx_frame(struct sk_buff *, struct device *);
extern void nr_destroy_socket(struct sock *);
-extern int nr_get_info(char *, char **, off_t, int, int);
+/*extern int nr_get_info(char *, char **, off_t, int, int);*/
/* nr_dev.c */
extern int nr_rx_ip(struct sk_buff *, struct device *);
ifdef CONFIG_MODVERSIONS
$(O_TARGET): $(SYMTAB_OBJS:.o=.ver)
+dep: $(SYMTAB_OBJS:.o=.ver)
+fastdep: $(SYMTAB_OBJS:.o=.ver)
endif
include $(TOPDIR)/Rules.make
/*
- * linux/mm/filemmap.c
+ * linux/mm/filemap.c
*
- * Copyright (C) 1994 Linus Torvalds
+ * Copyright (C) 1994, 1995 Linus Torvalds
*/
/*
#include <linux/mman.h>
#include <linux/string.h>
#include <linux/malloc.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
#include <asm/segment.h>
#include <asm/system.h>
/*
* Shared mappings implemented 30.11.1994. It's not fully working yet,
* though.
+ *
+ * Shared mappings now work. 15.8.1995 Bruno.
*/
-static inline void multi_bmap(struct inode * inode, unsigned int block, unsigned int * nr, int shift)
+/*
+ * Simple routines for both non-shared and shared mappings.
+ */
+
+static inline void multi_bmap(struct inode * inode, unsigned long block, unsigned int * nr, int shift)
{
int i = PAGE_SIZE >> shift;
block >>= shift;
return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, no_share);
}
+
/*
- * NOTE! mmap sync doesn't really work yet. This is mainly a stub for it,
- * which only works if the buffers and the page were already sharing the
- * same physical page (that's actually pretty common, especially if the
- * file has been mmap'ed before being read the normal way).
- *
- * Todo:
- * - non-shared pages also need to be synced with the buffers.
- * - the "swapout()" function needs to swap out the page to
- * the shared file instead of using the swap device.
+ * Tries to write a shared mapped page to its backing store. May return -EIO
+ * if the disk is full.
*/
-static void filemap_sync_page(struct vm_area_struct * vma,
+static int filemap_write_page(struct vm_area_struct * vma,
unsigned long offset,
unsigned long page)
{
+ int old_fs;
+ unsigned long size, result;
+ struct file file;
struct inode * inode;
- int nr[PAGE_SIZE/512];
struct buffer_head * bh;
bh = buffer_pages[MAP_NR(page)];
mark_buffer_dirty(tmp, 0);
tmp = tmp->b_this_page;
} while (tmp != bh);
- return;
+ return 0;
}
+
inode = vma->vm_inode;
- offset += vma->vm_offset;
- multi_bmap(inode, offset, nr, inode->i_sb->s_blocksize_bits);
- bwrite_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize);
+ file.f_op = inode->i_op->default_file_ops;
+ if (!file.f_op->write)
+ return -EIO;
+ size = offset + PAGE_SIZE;
+ /* refuse to extend file size.. */
+ if (S_ISREG(inode->i_mode)) {
+ if (size > inode->i_size)
+ size = inode->i_size;
+ /* Ho humm.. We should have tested for this earlier */
+ if (size < offset)
+ return -EIO;
+ }
+ size -= offset;
+ file.f_mode = 3;
+ file.f_flags = 0;
+ file.f_count = 1;
+ file.f_inode = inode;
+ file.f_pos = offset;
+ file.f_reada = 0;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ result = file.f_op->write(inode, &file, (const char *) page, size);
+ set_fs(old_fs);
+ if (result != size)
+ return -EIO;
+ return 0;
}
+
/*
* Swapping to a shared file: while we're busy writing out the page
* (and the page still exists in memory), we save the page information
*
* Once we've written it all out, we mark the page entry "empty", which
* will result in a normal page-in (instead of a swap-in) from the now
- * up-to-date shared file mapping.
+ * up-to-date disk file.
*/
-void filemap_swapout(struct vm_area_struct * vma,
+int filemap_swapout(struct vm_area_struct * vma,
unsigned long offset,
pte_t *page_table)
{
+ int error;
unsigned long page = pte_page(*page_table);
unsigned long entry = SWP_ENTRY(SHM_SWP_TYPE, MAP_NR(page));
pte_val(*page_table) = entry;
invalidate();
- filemap_sync_page(vma, offset, page);
+ error = filemap_write_page(vma, offset, page);
if (pte_val(*page_table) == entry)
pte_clear(page_table);
+ return error;
}
/*
mem_map[page]++;
page = (page << PAGE_SHIFT) + PAGE_OFFSET;
- return pte_mkdirty(mk_pte(page,vma->vm_page_prot));
+ return mk_pte(page,vma->vm_page_prot);
}
-static inline void filemap_sync_pte(pte_t * pte, struct vm_area_struct *vma,
+
+static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
unsigned long address, unsigned int flags)
{
- pte_t page = *pte;
-
- if (!pte_present(page))
- return;
- if (!pte_dirty(page))
- return;
- if (flags & MS_INVALIDATE) {
- pte_clear(pte);
+ pte_t pte = *ptep;
+ unsigned long page;
+ int error;
+
+ if (!(flags & MS_INVALIDATE)) {
+ if (!pte_present(pte))
+ return 0;
+ if (!pte_dirty(pte))
+ return 0;
+ *ptep = pte_mkclean(pte);
+ page = pte_page(pte);
+ mem_map[MAP_NR(page)]++;
} else {
- mem_map[MAP_NR(pte_page(page))]++;
- *pte = pte_mkclean(page);
+ if (pte_none(pte))
+ return 0;
+ pte_clear(ptep);
+ if (!pte_present(pte)) {
+ swap_free(pte_val(pte));
+ return 0;
+ }
+ page = pte_page(pte);
+ if (!pte_dirty(pte) || flags == MS_INVALIDATE) {
+ free_page(page);
+ return 0;
+ }
}
- filemap_sync_page(vma, address - vma->vm_start, pte_page(page));
- free_page(pte_page(page));
+ error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page);
+ free_page(page);
+ return error;
}
-static inline void filemap_sync_pte_range(pmd_t * pmd,
+static inline int filemap_sync_pte_range(pmd_t * pmd,
unsigned long address, unsigned long size,
struct vm_area_struct *vma, unsigned long offset, unsigned int flags)
{
pte_t * pte;
unsigned long end;
+ int error;
if (pmd_none(*pmd))
- return;
+ return 0;
if (pmd_bad(*pmd)) {
printk("filemap_sync_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
pmd_clear(pmd);
- return;
+ return 0;
}
pte = pte_offset(pmd, address);
offset += address & PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
+ error = 0;
do {
- filemap_sync_pte(pte, vma, address + offset, flags);
+ error |= filemap_sync_pte(pte, vma, address + offset, flags);
address += PAGE_SIZE;
pte++;
} while (address < end);
+ return error;
}
-static inline void filemap_sync_pmd_range(pgd_t * pgd,
+static inline int filemap_sync_pmd_range(pgd_t * pgd,
unsigned long address, unsigned long size,
struct vm_area_struct *vma, unsigned int flags)
{
pmd_t * pmd;
unsigned long offset, end;
+ int error;
if (pgd_none(*pgd))
- return;
+ return 0;
if (pgd_bad(*pgd)) {
printk("filemap_sync_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
pgd_clear(pgd);
- return;
+ return 0;
}
pmd = pmd_offset(pgd, address);
offset = address & PMD_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
+ error = 0;
do {
- filemap_sync_pte_range(pmd, address, end - address, vma, offset, flags);
+ error |= filemap_sync_pte_range(pmd, address, end - address, vma, offset, flags);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
+ return error;
}
-static void filemap_sync(struct vm_area_struct * vma, unsigned long address,
+static int filemap_sync(struct vm_area_struct * vma, unsigned long address,
size_t size, unsigned int flags)
{
pgd_t * dir;
unsigned long end = address + size;
+ int error = 0;
dir = pgd_offset(current, address);
while (address < end) {
- filemap_sync_pmd_range(dir, address, end - address, vma, flags);
+ error |= filemap_sync_pmd_range(dir, address, end - address, vma, flags);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
}
invalidate();
- return;
+ return error;
}
/*
- * This handles area unmaps..
+ * This handles partial area unmaps..
*/
static void filemap_unmap(struct vm_area_struct *vma, unsigned long start, size_t len)
{
};
/*
- * Private mappings just need to be able to load in the map
+ * Private mappings just need to be able to load in the map.
*
- * (this is actually used for shared mappings as well, if we
+ * (This is actually used for shared mappings as well, if we
* know they can't ever get write permissions..)
*/
static struct vm_operations_struct file_private_mmap = {
{
struct vm_operations_struct * ops;
- if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
- return -EINVAL;
+ if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) {
+ ops = &file_shared_mmap;
+ /* share_page() can only guarantee proper page sharing if
+ * the offsets are all page aligned. */
+ if (vma->vm_offset & (PAGE_SIZE - 1))
+ return -EINVAL;
+ } else {
+ ops = &file_private_mmap;
+ if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
+ return -EINVAL;
+ }
if (!inode->i_sb || !S_ISREG(inode->i_mode))
return -EACCES;
if (!inode->i_op || !inode->i_op->bmap)
return -ENOEXEC;
- ops = &file_private_mmap;
- if (vma->vm_flags & VM_SHARED) {
- if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
- ops = &file_shared_mmap;
- }
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
vma->vm_ops = ops;
return 0;
}
+
+
+/*
+ * The msync() system call.
+ */
+
+static int msync_interval(struct vm_area_struct * vma,
+ unsigned long start, unsigned long end, int flags)
+{
+ if (!vma->vm_inode)
+ return 0;
+ if (vma->vm_ops->sync) {
+ int error;
+ error = vma->vm_ops->sync(vma, start, end-start, flags);
+ if (error)
+ return error;
+ if (flags & MS_SYNC)
+ return file_fsync(vma->vm_inode, NULL);
+ return 0;
+ }
+ return 0;
+}
+
+asmlinkage int sys_msync(unsigned long start, size_t len, int flags)
+{
+ unsigned long end;
+ struct vm_area_struct * vma;
+ int unmapped_error, error;
+
+ if (start & ~PAGE_MASK)
+ return -EINVAL;
+ len = (len + ~PAGE_MASK) & PAGE_MASK;
+ end = start + len;
+ if (end < start)
+ return -EINVAL;
+ if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
+ return -EINVAL;
+ if (end == start)
+ return 0;
+ /*
+ * If the interval [start,end) covers some unmapped address ranges,
+ * just ignore them, but return -EFAULT at the end.
+ */
+ vma = find_vma(current, start);
+ unmapped_error = 0;
+ for (;;) {
+ /* Still start < end. */
+ if (!vma)
+ return -EFAULT;
+ /* Here start < vma->vm_end. */
+ if (start < vma->vm_start) {
+ unmapped_error = -EFAULT;
+ start = vma->vm_start;
+ }
+ /* Here vma->vm_start <= start < vma->vm_end. */
+ if (end <= vma->vm_end) {
+ if (start < end) {
+ error = msync_interval(vma, start, end, flags);
+ if (error)
+ return error;
+ }
+ return unmapped_error;
+ }
+ /* Here vma->vm_start <= start < vma->vm_end < end. */
+ error = msync_interval(vma, start, vma->vm_end, flags);
+ if (error)
+ return error;
+ start = vma->vm_end;
+ vma = vma->vm_next;
+ }
+}
extern int shm_swap (int, unsigned long);
+/*
+ * To save us from swapping out pages which have just been swapped in and
+ * have not been modified since then, we keep in swap_cache[page>>PAGE_SHIFT]
+ * the swap entry which was last used to fill the page, or zero if the
+ * page does not currently correspond to a page in swap. PAGE_DIRTY makes
+ * this info useless.
+ */
unsigned long *swap_cache;
#ifdef SWAP_CACHE_INFO
return 0;
}
if (pte_dirty(pte)) {
- if (mem_map[MAP_NR(page)] != 1)
- return 0;
if (vma->vm_ops && vma->vm_ops->swapout) {
+ pid_t pid = vma->vm_task->pid;
vma->vm_task->mm->rss--;
- vma->vm_ops->swapout(vma, address-vma->vm_start, page_table);
+ if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table))
+ kill_proc(pid, SIGBUS, 1);
} else {
+ if (mem_map[MAP_NR(page)] != 1)
+ return 0;
if (!(entry = get_swap_page()))
return 0;
vma->vm_task->mm->rss--;
------->>>>> 1.3.14 <<<<<----------
-o IPX works [IN]
-o NetROM works [IN]
-o AX.25 works [IN]
+o IPX works [TESTED]
+o NetROM works [TESTED]
+o AX.25 works [TESTED]
o Most modules need recompiling even though they
load OK [BLAME LINUS]
o Appletalk works nicely [CHECKED]
------->>>>> 1.3.15 <<<<<---------
o Mike Shaver has started RFC1122 verification [IN PROGRESS]
-o Minor bug fixes [IN]
+o Minor bug fixes [TESTED]
------->>>> 1.3.16 <<<--------
o Missing patches for device change in TCP [TESTED]
o Device locking [TESTED]
-o Infinite slip devices [IN]
-o New AF_UNIX sockets [IN]
+o Infinite slip devices [IN - BUG]
+o New AF_UNIX sockets [TESTED]
o Sendmsg/recvmsg (for some stuff only) [IN]
o Device unload loopholes fixed [TESTED]
o Extra firewall abilities [IN]
------->>>> 1.3.18 <<<<---------
-o AF_UNIX debugging [IN]
-o TCP explode on SWS bug fix [IN]
-o John Naylor's ARP hwtype fix [IN]
-o Datagram select matches BSD semantics [IN]
+o AF_UNIX debugging [TESTED]
+o TCP explode on SWS bug fix [TESTED]
+o John Naylor's ARP hwtype fix [TESTED]
+o Datagram select matches BSD semantics [TESTED]
+-------->>>>> 1.3.21 <<<<<---------
+
+o AF_UNIX fixes and 4K limiter [IN]
+o Sendmsg/recvmsg for AX.25/Appletalk [IN]
+o Datagram generic iovec support [IN]
+o Misc minor bug fixes [IN]
o Finish merging the bridge code
o SIOCSLEEPRT patch
o Fast checksum/copy on outgoing TCP
o Fast dev_grab_next() transmit reload function
and dev_push_failed() ??
-o Faster ip_forward last hit cache [PENDING]
+o Faster ip_forward last hit cache [PENDING(GuruA0)]
o Forwarding queue control (+ fairness algorithms ??)
o IP forward flow control.
o Infinite PPP devices.
o Finish 802.2 Class I code to be compliant to the oddities of 802.2
o Full variable length AX.25 support [JSN doing]
o Tidy BPQ support
+o Strange eth0-eth3 bug
+o Finish IPIP bug fixes
+o Why doesnt the PROTO_UNREACH get sent ?
+
0.2
---
17. PPP multilink. Another nasty job.
18. Implement swIPe under Linux.
-[In progress]
+[Reportedly in progress]
19. IPv4 IP-AH and IP-ESP.
+[Taken]
BTW: Don't let the magic words 'kernel programming' worry you. Its like DOS
- you make a mistake you have to reboot. You do at least get dumps and a
* Michael Callahan : Made routing work
* Wesley Craig : Fix probing to listen to a
* passed node id.
+ * Alan Cox : Added send/recvmsg support
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
return(0);
}
-static int atalk_sendto(struct socket *sock, const void *ubuf, int len, int noblock,
- unsigned flags, struct sockaddr *sat, int addr_len)
+static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
{
atalk_socket *sk=(atalk_socket *)sock->data;
- struct sockaddr_at *usat=(struct sockaddr_at *)sat;
+ struct sockaddr_at *usat=(struct sockaddr_at *)msg->msg_name;
struct sockaddr_at local_satalk, gsat;
struct sk_buff *skb;
struct device *dev;
return -EBUSY;
}
- if(addr_len <sizeof(*usat))
+ if(msg->msg_namelen <sizeof(*usat))
return(-EINVAL);
if(usat->sat_family != AF_APPLETALK)
return -EINVAL;
if(sk->debug)
printk("SK %p: Copy user data (%d bytes).\n", sk, len);
- memcpy_fromfs(skb_put(skb,len),ubuf,len);
+ memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len);
if(sk->no_check==1)
ddp->deh_sum=0;
return len;
}
+
+static int atalk_sendto(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags,
+ struct sockaddr *sa, int addr_len)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ iov.iov_base=(void *)ubuf;
+ iov.iov_len=size;
+ msg.msg_name=(void *)sa;
+ msg.msg_namelen=addr_len;
+ msg.msg_accrights=NULL;
+ msg.msg_iov=&iov;
+ msg.msg_iovlen=1;
+ return atalk_sendmsg(sock,&msg,size,noblock,flags);
+}
+
+
static int atalk_send(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags)
{
return atalk_sendto(sock,ubuf,size,noblock,flags,NULL,0);
}
-static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sip, int *addr_len)
+static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
{
atalk_socket *sk=(atalk_socket *)sock->data;
- struct sockaddr_at *sat=(struct sockaddr_at *)sip;
+ struct sockaddr_at *sat=(struct sockaddr_at *)msg->msg_name;
struct ddpehdr *ddp = NULL;
int copied = 0;
struct sk_buff *skb;
copied=ddp->deh_len;
if(copied > size)
copied=size;
- skb_copy_datagram(skb,0,ubuf,copied);
+ skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied);
}
else
{
copied=ddp->deh_len - sizeof(*ddp);
if (copied > size)
copied = size;
- skb_copy_datagram(skb,sizeof(*ddp),ubuf,copied);
+ skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied);
}
if(sat)
{
}
+static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags,
+ struct sockaddr *sa, int *addr_len)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ iov.iov_base=ubuf;
+ iov.iov_len=size;
+ msg.msg_name=(void *)sa;
+ msg.msg_namelen=0;
+ if (addr_len)
+ msg.msg_namelen = *addr_len;
+ msg.msg_accrights=NULL;
+ msg.msg_iov=&iov;
+ msg.msg_iovlen=1;
+ return atalk_recvmsg(sock,&msg,size,noblock,flags,addr_len);
+}
+
static int atalk_recv(struct socket *sock, void *ubuf, int size , int noblock,
unsigned flags)
{
atalk_setsockopt,
atalk_getsockopt,
atalk_fcntl,
+ atalk_sendmsg,
+ atalk_recvmsg
};
static struct notifier_block ddp_notifier={
atalk_if_get_info
});
- printk("Appletalk BETA 0.11 for Linux NET3.030\n");
+ printk("Appletalk BETA 0.12 for Linux NET3.030\n");
}
#endif
return ax25_rcv(skb, dev, &port_call, ptype);
}
-static int ax25_sendto(struct socket *sock, const void *ubuf, int len, int noblock,
- unsigned flags, struct sockaddr *usip, int addr_len)
+static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, int noblock, int flags)
{
struct sock *sk = (struct sock *)sock->data;
- struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)usip;
- unsigned char *uaddr = (unsigned char *)usip;
+ struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
+ unsigned char *uaddr = (unsigned char *)msg->msg_name;
int err;
struct sockaddr_ax25 sax;
struct sk_buff *skb;
ax25_digi *dp;
ax25_digi dtmp;
int lv;
+ int addr_len=msg->msg_namelen;
if (sk->err) {
+ cli();
err = sk->err;
sk->err = 0;
+ sti();
return -err;
}
- if (flags)
+ if (flags|| msg->msg_accrights)
return -EINVAL;
if (sk->zapped)
printk("AX.25: Appending user data\n");
/* User data follows immediately after the AX.25 data */
- memcpy_fromfs(skb_put(skb, len), ubuf, len);
+ memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
/* Add the PID, usually AX25_TEXT */
asmptr = skb_push(skb, 1);
}
+static int ax25_sendto(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags,
+ struct sockaddr *sa, int addr_len)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ iov.iov_base=(void *)ubuf;
+ iov.iov_len=size;
+ msg.msg_name=(void *)sa;
+ msg.msg_namelen=addr_len;
+ msg.msg_accrights=NULL;
+ msg.msg_iov=&iov;
+ msg.msg_iovlen=1;
+ return ax25_sendmsg(sock,&msg,size,noblock,flags);
+}
+
+
static int ax25_send(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags)
{
return ax25_sendto(sock, ubuf, size, noblock, flags, NULL, 0);
static int ax25_write(struct socket *sock, const char *ubuf, int size, int noblock)
{
- return ax25_send(sock, ubuf, size, noblock, 0);
+ return ax25_sendto(sock, ubuf, size, noblock, 0, NULL, 0);
}
-static int ax25_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sip, int *addr_len)
+static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
{
struct sock *sk = (struct sock *)sock->data;
- struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)sip;
- char *addrptr = (char *)sip;
+ struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
+ char *addrptr = (char *)msg->msg_name;
int copied, length;
struct sk_buff *skb;
int er;
if (sk->err) {
+ cli();
er = -sk->err;
sk->err = 0;
+ sti();
return er;
}
}
copied = (size < length) ? size : length;
- skb_copy_datagram(skb, 0, ubuf, copied);
+ skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (sax) {
struct sockaddr_ax25 addr;
return copied;
}
+static int ax25_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags,
+ struct sockaddr *sa, int *addr_len)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ iov.iov_base=ubuf;
+ iov.iov_len=size;
+ msg.msg_name=(void *)sa;
+ msg.msg_namelen=0;
+ if (addr_len)
+ msg.msg_namelen = *addr_len;
+ msg.msg_accrights=NULL;
+ msg.msg_iov=&iov;
+ msg.msg_iovlen=1;
+ return ax25_recvmsg(sock,&msg,size,noblock,flags,addr_len);
+}
+
static int ax25_recv(struct socket *sock, void *ubuf, int size , int noblock,
unsigned flags)
{
ax25_setsockopt,
ax25_getsockopt,
ax25_fcntl,
+ ax25_sendmsg,
+ ax25_recvmsg
};
/* Called by socket.c on kernel start up */
O_TARGET := core.o
-O_OBJS :=
+O_OBJS := sock.o skbuff.o iovec.o datagram.o
ifdef CONFIG_NET
-O_OBJS += sock.o dev.o dev_mcast.o iovec.o skbuff.o datagram.o
+O_OBJS += dev.o dev_mcast.o
endif
include $(TOPDIR)/Rules.make
* Florian La Roche: Changed for my new skbuff handling.
* Darryl Miles : Fixed non-blocking SOCK_SEQPACKET.
* Linus Torvalds : BSD semantic fixes.
+ * Alan Cox : Datagram iovec handling
*
* Note:
* A lot of this will change when the protocol/socket separation
restore_flags(flags);
}
+/*
+ * Copy a datagram to a linear buffer.
+ */
+
void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
{
memcpy_tofs(to,skb->h.raw+offset,size);
}
+
+/*
+ * Copy a datagram to an iovec.
+ */
+
+void skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, int size)
+{
+ memcpy_toiovec(to,skb->h.raw+offset,size);
+}
+
/*
* Datagram select: Again totally generic. Moved from udp.c
* Now does seqpacket.
{
while(len>0)
{
- memcpy_tofs(iov->iov_base, kdata,iov->iov_len);
- kdata+=iov->iov_len;
- len-=iov->iov_len;
+ int copy = min(iov->iov_len,len);
+ memcpy_tofs(iov->iov_base,kdata,copy);
+ kdata+=copy;
+ len-=copy;
iov++;
}
}
extern int tcp_get_info(char *, char **, off_t, int, int);
extern int udp_get_info(char *, char **, off_t, int, int);
-int (*rarp_ioctl_hook)(int,void*) = NULL;
+int (*rarp_ioctl_hook)(unsigned int,void*) = NULL;
/*
* See if a socket number is in use.
* Check for bad requests for 127.x.x.x and requests for multicast
* addresses. If this is one such, delete it.
*/
- if (IN_LOOPBACK(tip) || IN_MULTICAST(tip))
+ if (LOOPBACK(tip) || MULTICAST(tip))
{
kfree_skb(skb, FREE_READ);
return 0;
(OK... we don't use it)
MUST discard received REPLYs if not using this system (OK)
MUST NOT send replies unless specifically made agent for this sort
- of thing. (NOT YET)
+ of thing. (OK)
*/
#include <linux/types.h>
return mac;
}
+static int ip_send_room(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, unsigned long saddr)
+{
+ int mac = 0;
+
+ skb->dev = dev;
+ skb->arp = 1;
+ if (dev->hard_header)
+ {
+ skb_reserve(skb,MAX_HEADER);
+ mac = dev->hard_header(skb, dev, ETH_P_IP, NULL, NULL, len);
+ if (mac < 0)
+ {
+ mac = -mac;
+ skb->arp = 0;
+ skb->raddr = daddr; /* next routing address */
+ }
+ }
+ return mac;
+}
+
int ip_id_count = 0;
/*
* Now build the MAC header.
*/
- tmp = ip_send(skb, raddr, len, *dev, saddr);
+ if(type==IPPROTO_TCP)
+ tmp = ip_send_room(skb, raddr, len, *dev, saddr);
+ else
+ tmp = ip_send(skb, raddr, len, *dev, saddr);
/*
* Book keeping
int err;
#endif
+#ifdef CONFIG_NET_IPV6
+ /*
+ * Intercept IPv6 frames. We dump ST-II and invalid types just below..
+ */
+
+ if(iph->version == 6)
+ return ipv6_rcv(skb,dev,pt);
+#endif
+
ip_statistics.IpInReceives++;
/*
{
struct sock *sknext=NULL;
struct sk_buff *skb1;
- raw_sk=get_sock_raw(raw_sk, hash, iph->saddr, iph->daddr);
+ raw_sk=get_sock_raw(raw_sk, iph->protocol, iph->saddr, iph->daddr);
if(raw_sk) /* Any raw sockets */
{
do
{
/* Find the next */
- sknext=get_sock_raw(raw_sk->next, hash, iph->saddr, iph->daddr);
+ sknext=get_sock_raw(raw_sk->next, iph->protocol, iph->saddr, iph->daddr);
if(sknext)
skb1=skb_clone(skb, GFP_ATOMIC);
else
#ifdef CONFIG_IP_MASQUERADE
static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
- int length)
+ int length, int unused)
{
off_t pos=0, begin=0;
struct ip_masq *ms;
* until we time out, or the user gives up.
*/
- if (icmp_err_convert[err & 0xff].fatal || sk->state == TCP_SYN_SENT)
+ if (err < 13 && (icmp_err_convert[err & 0xff].fatal || sk->state == TCP_SYN_SENT))
{
if (sk->state == TCP_SYN_SENT)
{
/* 4.1.3.3. */
/* After the comment above, that should be no surprise. */
- if (icmp_err_convert[err & 0xff].fatal)
+ if (err < 13 && icmp_err_convert[err & 0xff].fatal)
{
sk->err = icmp_err_convert[err & 0xff].errno;
sk->error_report(sk);
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
+#include <linux/stat.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/proc_fs.h>
#include <net/ip.h>
#include <net/arp.h>
-
+#include <linux/if_arp.h>
#include <linux/proc_fs.h>
/************************************************************************\
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_NR, 2, "nr",
S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
nr_get_info
});
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_NR_NEIGH, 8, "nr_neigh",
S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
nr_neigh_get_info
});
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_NR_NODES, 8, "nr_nodes",
S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
nr_nodes_get_info
});
}
#include <net/ip.h>
#include <net/arp.h>
+#include <linux/if_arp.h>
#include <net/ax25.h>
#include <net/netrom.h>
*
* Currently this contains all but the file descriptor passing code.
* Before that goes in the odd bugs in the iovec handlers need
- * fixing, and this bit testing. BSD fd passing is a trivial part
- * of the exercise.
+ * fixing, and this bit testing. BSD fd passing is not a trivial part
+ * of the exercise it turns out. Anyone like writing garbage collectors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
*
* Fixes:
* Linus Torvalds : Assorted bug cures.
- * Niibe Yutaka : async I/O support
+ * Niibe Yutaka : async I/O support.
* Carsten Paeth : PF_UNIX check, address fixes.
+ * Alan Cox : Limit size of allocated blocks.
*/
#include <linux/config.h>
if(sun==NULL)
{
if(sk->protinfo.af_unix.other==NULL)
- return -EINVAL;
+ return -ENOTCONN;
}
/*
if(sock->type==SOCK_DGRAM)
return -EMSGSIZE;
len=(sk->sndbuf-sizeof(struct sk_buff))/2;
+ /*
+ * Keep to page sized kmalloc()'s as various people
+ * have suggested. Big mallocs stress the vm too
+ * much.
+ */
+ if(len > 4000 && sock->type!=SOCK_DGRAM)
+ len = 4000;
}
size=/*protocol_size(&proto_unix)+*/len;
void unix_proto_init(struct net_proto *pro)
{
- printk("NET3: Unix domain sockets 0.07 BETA for Linux NET3.030.\n");
+ printk("NET3: Unix domain sockets 0.09 BETA for Linux NET3.030.\n");
sock_register(unix_proto_ops.family, &unix_proto_ops);
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_UNIX, 4, "unix",
return "Yes"
} else {return ""}
}
- ERRNO=""
- getline dummy < f
- if(!length(ERRNO)) {
+ ERRNO = getline dummy < f
+ if(ERRNO >= 0) {
close(f)
return FILEHASH[f]="Yes"
} else {
do echo "#include <linux/modules/$${f}>"; done) \
> $(TOPINCL)/modversions.h
-dep: $(TOPINCL)/modversions.h
+fastdep: $(TOPINCL)/modversions.h
endif