VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 22
+SUBLEVEL = 23
all: Version zImage
* data (18*2*512 bytes).
*/
_floppy_track_buffer:
- .fill 512*2*18,1,0
+ .fill 512*2*36,1,0
/* This is the default interrupt "handler" :-) */
int_msg:
-This README belongs to release 1.6 of the SoundBlaster Pro (Matsushita,
+This README belongs to release 2.0 of the SoundBlaster Pro (Matsushita,
Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux.
The driver is able to drive the whole family of IDE-style
Matsushita/Kotobuki/Panasonic drives (the "double speed" versions like CR-562
and CR-563, too), and it will work with the soundcard interfaces (SB Pro,
SB 16, Galaxy, SoundFX, ...) and/or with the "no-sound" cards (Panasonic
-CI-101P, LaserMate, Aztech, ...).
+CI-101P, LaserMate, WDH-7001C, Aztech, ...).
It should work too now with the "configurable" interface "Sequoia S-1000",
which is found on the Spea Media FX sound card.
The interface type has to get configured in /usr/include/linux/sbpcd.h,
(which count the releases around 0.75 or 1.00).
Up to 4 drives are supported. CR-52x ("old") and CR-56x ("new") drives can be
-mixed, but the CR-521 ones are hard-wired to drive ID 0.
+mixed, but the CR-521 ones are hard-wired to drive ID 0. The drives have to
+use different drive IDs, and each drive has to get a unique minor number
+(0...3), corresponding to it's drive ID. The drive IDs may be selected freely
+from 0 to 3 - they must not be in consecutive order.
As Don Carroll, don@ds9.us.dell.com or FIDO 1:382/14, told me, it is possible
to change old drives to any ID, too. He writes in this sense:
did not work with other values. If the values are not good,
ID 3 behaves like ID 0."
-The drives have to use different drive IDs, but the same controller (it will
-be a little bit harder to support up to four interface cards - but I plan to
-do it the day somebody wishes to connect a fifth drive).
-Each drive has to get a unique minor number (0...3), corresponding to it's
-drive ID. The drive IDs may be selected freely from 0 to 3 - they must not be
-in consecutive order.
+To use more than 4 drives (now that the single-speed CR-521's are as cheap as
+50$), you have to "duplicate" the driver. Just copy sbpcd.c into sbpcd2.c and
+change SBPCD_ISSUE accordingly.
The driver supports reading of data from the CD and playing of audio tracks.
The audio part should run with WorkMan, xcdplayer, with the "non-X11" products
CDplayer and WorkBone - tell me if it is not compatible with other software.
+With the "new" drive family CR-562 and CR-563, the reading of audio frames is
+possible. This is currently implemented by an IOCTL function which reads only
+one frame of 2352 bytes at a time. The transfer rate is as slow as 32 kB/sec.
+This will get better, and the software interface may change. We have to
+standardize it the day the SCSI driver supports it too.
+
MultiSession is supported (even my "old" CR-521 can handle it), "ManySession"
(not recommended, see below) alternatively.
Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's
So, if the DOS driver tells you have drive id #3, you have to
mknod /dev/<any_name> b 25 3
+ For a second interface board, you have to make nodes like
+ mknod /dev/sbpcd4 b 26 0
+ and so on. Use the MAJORs 26, 27, 28.
+
If you further make a link like
ln -s sbpcd /dev/cdrom
you can use the name /dev/cdrom, too.
If you enable this feature, it is impossible to read true multisession CDs.
The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to
-specify "block=2048" as a mount option.
+specify "block=2048" as a mount option. Doing this will disable the direct
+execution of a binary from the CD; you have to copy it to a device with the
+standard BLOCK_SIZE (1024) before. So, do not use this if your system is
+directly "running from the CDROM" (like some of YGGDRASIL's installation
+variants). There are CDs on the market (like the german "unifix" Linux
+distribution) which MUST get handled with a block_size of 1024.
Auto-probing at boot time:
them without the need of supplying parameters.
+Copying audio tracks:
+---------------------
+
+The following little program will copy track 2 of an audio CD into the file
+"track02":
+
+/*=================== begin program ========================================*/
+/*
+ * read an audio track from a CD
+ *
+ * (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
+ * may be used & enhanced freely
+ *
+ * Due to non-existent sync bytes at the beginning of each audio frame,
+ * it is currently a kind of fortune if two consecutive frames fit together.
+ * Usually, they overlap, or a little piece is missing. This has to get
+ * fixed by higher-level software (reading until an overlap occurs, and then
+ * eliminate the overlapping bytes). Possibly the first read bytes of each
+ * frame must get discarded because they are read before we got synchronized.
+ *
+ * This example program further is missing to obtain the SubChannel data
+ * which belong to each frame.
+ */
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+
+static struct cdrom_tochdr hdr;
+static struct cdrom_tocentry entry[100];
+static struct cdrom_read_audio arg;
+static u_char buffer[CD_FRAMESIZE_RAW];
+static int datafile, drive;
+static int i, j, limit, track, err;
+static char filename[32];
+
+main(int argc, char *argv[])
+{
+/*
+ * open /dev/cdrom
+ */
+ drive=open("/dev/cdrom", 0);
+ if (drive<0)
+ {
+ fprintf(stderr, "can't open drive.\n");
+ exit (-1);
+ }
+/*
+ * get TocHeader
+ */
+ fprintf(stdout, "getting TocHeader...\n");
+ err=ioctl(drive, CDROMREADTOCHDR, &hdr);
+ if (err!=0)
+ {
+ fprintf(stderr, "can't get TocHeader (error %d).\n", err);
+ exit (-1);
+ }
+ else
+ fprintf(stdout, "TocHeader: %d %d\n", hdr.cdth_trk0, hdr.cdth_trk1);
+/*
+ * get and display all TocEntries
+ */
+ fprintf(stdout, "getting TocEntries...\n");
+ for (i=1;i<=hdr.cdth_trk1;i++)
+ {
+ entry[i].cdte_track = i;
+ entry[i].cdte_format = CDROM_LBA;
+ err=ioctl(drive, CDROMREADTOCENTRY, &entry[i]);
+ if (err!=0)
+ {
+ fprintf(stderr, "can't get TocEntry #%d (error %d).\n", i, err);
+ exit (-1);
+ }
+ else
+ {
+ fprintf(stdout, "TocEntry #%d: %1X %1X %06X %02X\n",
+ entry[i].cdte_track,
+ entry[i].cdte_adr,
+ entry[i].cdte_ctrl,
+ entry[i].cdte_addr.lba,
+ entry[i].cdte_datamode);
+ }
+ }
+ fprintf(stdout, "got all TocEntries.\n");
+/*
+ * ask for track number (not implemented here)
+ */
+track=2;
+#if 0 /* just read a little piece */
+entry[track].cdte_addr.lba=170;
+entry[track+1].cdte_addr.lba=190;
+#endif
+/*
+ * read track into file
+ */
+ sprintf(filename, "track%02d\0", track);
+ datafile=creat(filename, 0755);
+ if (datafile<0)
+ {
+ fprintf(stderr, "can't open datafile %s.\n", filename);
+ exit (-1);
+ }
+ arg.addr.lba=entry[track].cdte_addr.lba;
+ arg.addr_format=CDROM_LBA; /* CDROM_MSF is still buggy, I know that */
+ arg.nframes=1;
+ arg.buf=&buffer[0];
+ limit=entry[track+1].cdte_addr.lba;
+ for (i=arg.addr.lba;i<limit;i++)
+ {
+ err=ioctl(drive, CDROMREADAUDIO, &arg);
+ if (err!=0)
+ {
+ fprintf(stderr, "can't read frame #%d (error %d).\n",
+ i-entry[track].cdte_addr.lba+1, err);
+ exit (-1);
+ }
+ j=write(datafile, &buffer[0], CD_FRAMESIZE_RAW);
+ if (j!=CD_FRAMESIZE_RAW)
+ {
+ fprintf(stderr,"I/O error (datafile) at frame %d\n",
+ i-entry[track].cdte_addr.lba+1);
+ }
+ arg.addr.lba++;
+ }
+}
+/*===================== end program ========================================*/
+
+
Known problems:
---------------
drives are telling there is no UPC/EAN code on disk or there is, but it is an
all-zero number.
-My attempts to read audio tracks like data files are of no success. Contact me,
-if you have an idea, please.
-
Bug reports, comments, wishes, donations (technical information is a donation,
too :-) etc. to
emoenke@gwdg.de
* work.
*/
+/* 1994/6/24 --bbroad-- added the floppy table entries and made
+ * minor modifications to allow 2.88 floppies to be run.
+ */
+
+
#define REALLY_SLOW_IO
#define FLOPPY_IRQ 6
#define FLOPPY_DMA 2
+#define FDC_FIFO_UNTESTED /* -bb */
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/dma.h>
+#include <asm/irq.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
* Maximum disk size (in kilobytes). This default is used whenever the
* current disk size is unknown.
*/
-#define MAX_DISK_SIZE 1440
+#define MAX_DISK_SIZE 2880 /* was 1440 -bb */
/*
* Maximum number of sectors in a track buffer. Track buffering is disabled
* if tracks are bigger.
*/
-#define MAX_BUFFER_SECTORS 18
+#define MAX_BUFFER_SECTORS 36 /* was 18 -bb */
+
/*
* The DMA channel used by the floppy controller cannot access data at
{ 720, 9,2,40,1,0x23,0x01,0xDF,0x50,NULL }, /* 360kB in 1.2MB drive */
{ 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,NULL }, /* 720kB in 1.2MB drive */
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }, /* 1.44MB diskette */
+ { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,NULL }, /* 2.88MB diskette */
+ { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,NULL }, /* 2.88MB diskette */
};
/*
{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" }, /* 3.5" 720kB diskette */
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M" }, /* 1.44MB diskette */
{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k/AT" }, /* 3.5" 720kB diskette */
+ { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"2.88M-AMI" }, /* DUMMY */
+ { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M-AMI" }, /* Dummy */
+ { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"2.88M" }, /* 2.88MB diskette */
+ { 2880,18,2,80,0,0x1B,0x40,0xCF,0x6C,"1.44MX" }, /* 1.44MB diskette */
};
/* Auto-detection: Disk type used until the next media change occurs. */
static int floppy_sizes[] ={
MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE,
- 360, 360 ,360, 360,
+ 360, 360, 360, 360,
1200,1200,1200,1200,
360, 360, 360, 360,
720, 720, 720, 720,
360, 360, 360, 360,
720, 720, 720, 720,
- 1440,1440,1440,1440
+ 1440,1440,1440,1440,
+ 2880,2880,2880,2880 /* -bb */
};
/*
extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
static void redo_fd_request(void);
+static void floppy_ready(void);
+static void recalibrate_floppy(void);
+
+static int floppy_grab_irq_and_dma(void);
+static void floppy_release_irq_and_dma(void);
/*
* These are global variables, as that's the easiest way to give
static unsigned char seek_track = 0;
static unsigned char current_track = NO_TRACK;
static unsigned char command = 0;
-static unsigned char fdc_version = FDC_TYPE_STD; /* FDC version code */
-
-static void floppy_ready(void);
+static unsigned char fdc_version = 0x90; /* FDC version code */
static void select_callback(unsigned long unused)
{
* Special case - used after a unexpected interrupt (or reset)
*/
-static void recalibrate_floppy(void);
-
static void recal_interrupt(void)
{
output_byte(FD_SENSEI);
{
struct floppy_struct *base;
- if (code > 0 && code < 5) {
+ if (code > 0 && code < 7) { /* -bb*/
base = &floppy_types[(code-1)*2];
printk("fd%d is %s",drive,base->name);
return base;
int drive;
int old_dev;
+ if (floppy_grab_irq_and_dma()) {
+ return -EBUSY;
+ }
drive = inode->i_rdev & 3;
old_dev = fd_device[drive];
if (fd_ref[drive])
printk("floppy_release with fd_ref == 0");
fd_ref[inode->i_rdev & 3] = 0;
}
+ floppy_release_irq_and_dma();
}
static struct file_operations floppy_fops = {
timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
timer_active &= ~(1 << FLOPPY_TIMER);
config_types();
- if (irqaction(FLOPPY_IRQ,&floppy_sigaction))
- printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ);
- if (request_dma(FLOPPY_DMA))
- printk("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA);
/* Try to determine the floppy controller type */
DEVICE_INTR = ignore_interrupt; /* don't ask ... */
output_byte(FD_VERSION); /* get FDC version code */
* properly, so force a reset for the standard FDC clones,
* to avoid interrupt garbage.
*/
-
if (fdc_version == FDC_TYPE_STD) {
initial_reset_flag = 1;
reset_floppy();
}
}
+
+static int floppy_grab_irq_and_dma(void)
+{
+ if (irqaction(FLOPPY_IRQ,&floppy_sigaction)) {
+ printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ);
+ return -1;
+ }
+ if (request_dma(FLOPPY_DMA)) {
+ printk("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA);
+ free_irq(FLOPPY_IRQ);
+ return -1;
+ }
+ enable_irq(FLOPPY_IRQ);
+ return 0;
+}
+
+static void floppy_release_irq_and_dma(void)
+{
+ disable_dma(FLOPPY_DMA);
+ free_dma(FLOPPY_DMA);
+ disable_irq(FLOPPY_IRQ);
+ free_irq(FLOPPY_IRQ);
+}
* and for "no-sound" interfaces like Lasermate and the
* Panasonic CI-101P.
*
- * NOTE: This is release 1.6.
+ * NOTE: This is release 2.0.
* It works with my SbPro & drive CR-521 V2.11 from 2/92
* and with the new CR-562-B V0.75 on a "naked" Panasonic
* CI-101P interface. And vice versa.
* called as it should I fear it must get synchronized for not to
* disturb the normal driver's activity.
*
+ * 2.0 Version number bumped - two reasons:
+ * - reading audio tracks as data works now with CR-562 and CR-563. We
+ * currently do it by an IOCTL (yet has to get standardized), one frame
+ * at a time; that is pretty slow. But it works.
+ * - we are maintaining now up to 4 interfaces (each up to 4 drives):
+ * did it the easy way - a different MAJOR (25, 26, ...) and a different
+ * copy of the driver (sbpcd.c, sbpcd2.c, sbpcd3.c, sbpcd4.c - only
+ * distinguished by the value of SBPCD_ISSUE and the driver's name),
+ * and a common sbpcd.h file.
+ * Bettered the "ReadCapacity error" problem with old CR-52x drives (the
+ * drives sometimes need a manual "eject/insert" before work): just
+ * reset the drive and do again. Needs lots of resets here and sometimes
+ * that does not cure, so this can't be the solution.
+ *
* special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
* elaborated speed-up experiments (and the fabulous results!), for
* the "push" towards load-free wait loops, and for the extensive mail
*
*/
+#define SBPCD_ISSUE 1 /* change to 2, 3, 4 for multiple interface boards */
+
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
+#include <linux/major.h>
#include <linux/sbpcd.h>
#include <linux/string.h>
-#include <linux/major.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <stdarg.h>
+#if !(SBPCD_ISSUE-1)
#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
+#endif
+#if !(SBPCD_ISSUE-2)
+#define MAJOR_NR MATSUSHITA_CDROM2_MAJOR /* second driver issue */
+#endif
+#if !(SBPCD_ISSUE-3)
+#define MAJOR_NR MATSUSHITA_CDROM3_MAJOR /* third driver issue */
+#endif
+#if !(SBPCD_ISSUE-4)
+#define MAJOR_NR MATSUSHITA_CDROM4_MAJOR /* fourth driver issue */
+#endif
+
#include "blk.h"
-#define VERSION "1.6 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "2.0 Eberhard Moenkeberg <emoenke@gwdg.de>"
#define SBPCD_DEBUG
#define XA_TEST2
#define TEST_UPC 0
-#define READ_AUDIO 0 /* does not work today (the drives won't read audio) */
-
+#define READ_AUDIO 1
+#define SPEA_TEST 0
+#define PRINTK_BUG 0
+#define TEST_STI 0
/*==========================================================================*/
+/*
+ * provisions for more than 1 driver issues
+ * currently up to 4 drivers, expandable
+ */
+#if !(SBPCD_ISSUE-1)
+#define SBPCD_IOCTL_F sbpcd_ioctl
+#define SBPCD_IOCTL(a,b,c,d) sbpcd_ioctl(a,b,c,d)
+#define DO_SBPCD_REQUEST(a) do_sbpcd_request(a)
+#define SBPCD_OPEN_F sbpcd_open
+#define SBPCD_OPEN(a,b) sbpcd_open(a,b)
+#define SBPCD_RELEASE_F sbpcd_release
+#define SBPCD_RELEASE(a,b) sbpcd_release(a,b)
+#define SBPCD_SETUP(a,b) sbpcd_setup(a,b)
+#define SBPCD_INIT(a,b) sbpcd_init(a,b)
+#define SBPCD_MEDIA_CHANGE(a,b) check_sbpcd_media_change(a,b)
+#endif
+#if !(SBPCD_ISSUE-2)
+#define SBPCD_IOCTL_F sbpcd2_ioctl
+#define SBPCD_IOCTL(a,b,c,d) sbpcd2_ioctl(a,b,c,d)
+#define DO_SBPCD_REQUEST(a) do_sbpcd2_request(a)
+#define SBPCD_OPEN_F sbpcd2_open
+#define SBPCD_OPEN(a,b) sbpcd2_open(a,b)
+#define SBPCD_RELEASE_F sbpcd2_release
+#define SBPCD_RELEASE(a,b) sbpcd2_release(a,b)
+#define SBPCD_SETUP(a,b) sbpcd2_setup(a,b)
+#define SBPCD_INIT(a,b) sbpcd2_init(a,b)
+#define SBPCD_MEDIA_CHANGE(a,b) check_sbpcd2_media_change(a,b)
+#endif
+#if !(SBPCD_ISSUE-3)
+#define SBPCD_IOCTL_F sbpcd3_ioctl
+#define SBPCD_IOCTL(a,b,c,d) sbpcd3_ioctl(a,b,c,d)
+#define DO_SBPCD_REQUEST(a) do_sbpcd3_request(a)
+#define SBPCD_OPEN_F sbpcd3_open
+#define SBPCD_OPEN(a,b) sbpcd3_open(a,b)
+#define SBPCD_RELEASE_F sbpcd3_release
+#define SBPCD_RELEASE(a,b) sbpcd3_release(a,b)
+#define SBPCD_SETUP(a,b) sbpcd3_setup(a,b)
+#define SBPCD_INIT(a,b) sbpcd3_init(a,b)
+#define SBPCD_MEDIA_CHANGE(a,b) check_sbpcd3_media_change(a,b)
+#endif
+#if !(SBPCD_ISSUE-4)
+#define SBPCD_IOCTL_F sbpcd4_ioctl
+#define SBPCD_IOCTL(a,b,c,d) sbpcd4_ioctl(a,b,c,d)
+#define DO_SBPCD_REQUEST(a) do_sbpcd4_request(a)
+#define SBPCD_OPEN_F sbpcd4_open
+#define SBPCD_OPEN(a,b) sbpcd4_open(a,b)
+#define SBPCD_RELEASE_F sbpcd4_release
+#define SBPCD_RELEASE(a,b) sbpcd4_release(a,b)
+#define SBPCD_SETUP(a,b) sbpcd4_setup(a,b)
+#define SBPCD_INIT(a,b) sbpcd4_init(a,b)
+#define SBPCD_MEDIA_CHANGE(a,b) check_sbpcd4_media_change(a,b)
+#endif
/*==========================================================================*/
-
#if MANY_SESSION
#undef LONG_TIMING
#define LONG_TIMING 1
0x340, 0, /* Lasermate, CI-101P */
0x360, 0, /* Lasermate, CI-101P */
0x270, 1, /* Soundblaster 16 */
- 0x630, 0, /* "sound card #9" (default) */
- 0x650, 0, /* "sound card #9" */
0x670, 0, /* "sound card #9" */
0x690, 0, /* "sound card #9" */
0x330, 2, /* SPEA Media FX (default) */
0x370, 0, /* Lasermate, CI-101P */
0x290, 1, /* Soundblaster 16 */
0x310, 0, /* Lasermate, CI-101P */
+/* excluded due to incomplete address decoding of the SbPro card */
+ 0x630, 0, /* "sound card #9" (default) */
+ 0x650, 0, /* "sound card #9" */
#endif
};
*/
static void sbp_read_cmd(void);
static int sbp_data(void);
+static int cmd_out(void);
/*==========================================================================*/
* (1<<DBG_LCK) door (un)lock info
* (1<<DBG_SQ) dump SubQ frame
* (1<<DBG_AUD) "read audio" debugging
+ * (1<<DBG_SEQ) Sequoia interface configuration trace
* (1<<DBG_000) unnecessary information
*/
#if 1
static int sbpcd_debug = (1<<DBG_INF) | (1<<DBG_WRN);
#else
+#if SPEA_TEST
+static int sbpcd_debug = (1<<DBG_INF) |
+ (1<<DBG_INI) |
+ (1<<DBG_ID) |
+ (1<<DBG_SEQ);
+#else
static int sbpcd_debug = (1<<DBG_INF) |
(1<<DBG_TOC) |
(1<<DBG_UPC) |
- (1<<DBG_IOC) |
- (1<<DBG_XA) |
+ (1<<DBG_TIM) |
(1<<DBG_LCK) |
(1<<DBG_CHK) |
(1<<DBG_AUD) |
- (1<<DBG_BSZ) |
(1<<DBG_IOX);
#endif
+#endif
static int sbpcd_ioaddr = CDROM_PORT; /* default I/O base address */
static int sbpro_type = SBPRO;
static int CDo_command, CDo_reset;
static struct cdrom_tocentry tocentry;
static struct cdrom_subchnl SC;
static struct cdrom_volctrl volctrl;
-char *str_sb = "SoundBlaster";
-char *str_lm = "LaserMate";
-char *str_sp = "SPEA";
+static struct cdrom_read_audio read_audio;
+static char *str_sb = "SoundBlaster";
+static char *str_lm = "LaserMate";
+static char *str_sp = "SPEA";
char *type;
/*==========================================================================*/
u_char mode; /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */
#if READ_AUDIO
- u_char *aud_buf; /* Pointer to internal data buffer,
+ u_char *aud_buf; /* Pointer to audio data buffer,
space allocated during sbpcd_init() */
#endif READ_AUDIO
#ifdef SBPCD_DEBUG
# define DPRINTF(x) sbpcd_dprintf x
-void sbpcd_dprintf(int level, char *fmt, ...)
+static void sbpcd_dprintf(int level, char *fmt, ...)
{
char buff[256];
va_list args;
vsprintf(buff, fmt, args);
va_end(args);
printk(buff);
+#if PRINTK_BUG
+ sti(); /* to avoid possible "printk" bug */
+#endif
}
#else
int i,j, st=0;
u_long timeout;
+ DPRINTF((DBG_000,"SBPCD: ResponseInfo entered.\n"));
if (current == task[0])
for (i=0;i<response_count;i++)
{
st=inb(CDi_status);
if (!(st&s_not_result_ready)) break;
}
- if (j==0) return (-1);
+ if (j==0)
+ {
+ DPRINTF((DBG_SEQ,"SBPCD: ResponseInfo: not_result_ready (got %d of %d bytes).\n", i, response_count));
+ return (-1);
+ }
infobuf[i]=inb(CDi_info);
}
else
infobuf[i]=inb(CDi_info);
}
}
+ DPRINTF((DBG_000,"SBPCD: ResponseInfo: done.\n"));
return (0);
}
/*==========================================================================*/
}
}
/*==========================================================================*/
-int xx_ReadError(void)
+static int xx_ReadError(void)
{
- int cmd_out(void);
int i;
clr_cmdbuf();
return (i);
}
/*==========================================================================*/
-int cmd_out(void)
+static int cmd_out(void)
{
int i=0;
DriveStruct[d].diskstate_flags &= ~frame_size_bit;
clr_cmdbuf();
DriveStruct[d].frame_size=framesize;
+ if (framesize==CD_FRAMESIZE_RAW) DriveStruct[d].sense_byte=0x82;
+ else DriveStruct[d].sense_byte=0x00;
DPRINTF((DBG_XA,"SBPCD: xx_ModeSelect: %02X %04X\n",
DriveStruct[d].sense_byte, DriveStruct[d].frame_size));
#ifdef CDMKE
int i=0;
+ DPRINTF((DBG_IOX,"SBPCD: check_datarate entered.\n"));
timed_out=0;
datarate=0;
+#if TEST_STI
+ for (i=0;i<=1000;i++) printk(".");
+#endif
+
/* set a timer to make (timed_out!=0) after 1.1 seconds */
DPRINTF((DBG_TIM,"SBPCD: timer started (110).\n"));
- sti(); /* to avoid possible "printf" bug */
-
SET_TIMER(mark_timeout,110);
do
{
{
int i, j;
+ DPRINTF((DBG_INI,"SBPCD: check_version entered.\n"));
/* clear any pending error state */
clr_cmdbuf();
drvcmd[0]=0x82;
response_count=9;
flags_cmd_out=f_putcmd;
- cmd_out();
+ i=cmd_out();
+ if (i<0) DPRINTF((DBG_INI,"SBPCD: cmd_82 returns %d (ok anyway).\n",i));
/* read drive version */
clr_cmdbuf();
else
{
for (i=0;i<8;i++) if (infobuf[i]!=drive_vendor[i]) break;
- if (i!=8) return (-1);
+ if (i!=8)
+ {
+ DPRINTF((DBG_INI,"SBPCD: check_version: error.\n"));
+ return (-1);
+ }
DriveStruct[d].drive_model[0]='2';
DriveStruct[d].drive_model[1]='x';
DriveStruct[d].drive_model[2]='-';
else if (j<211) DriveStruct[d].drv_type=drv_210;
else if (j<300) DriveStruct[d].drv_type=drv_211;
else DriveStruct[d].drv_type=drv_300;
+ DPRINTF((DBG_INI,"SBPCD: check_version done.\n"));
return (0);
}
/*==========================================================================*/
{
ndrives++;
DriveStruct[d].drv_options=drv_pattern[j];
- if (!new_drive) DriveStruct[d].drv_options&=~(speed_auto|speed_300|speed_150);
+ if (!new_drive)
+ DriveStruct[d].drv_options&=~(speed_auto|speed_300|speed_150);
printk("%sDrive %d: %s%.4s (%.4s)\n", printk_header,
DriveStruct[d].drv_minor,
drive_family,
/*==========================================================================*/
static int DiskInfo(void)
{
- int i;
+ int i, j;
#if READ_AUDIO
DriveStruct[d].mode=READ_M1;
#endif READ_AUDIO
- i=SetSpeed();
- if (i<0)
+#undef LOOP_COUNT
+#define LOOP_COUNT 20 /* needed for some "old" drives */
+
+ for (j=1;j<LOOP_COUNT;j++)
{
- DPRINTF((DBG_INF,"SBPCD: DiskInfo: first SetSpeed returns %d\n", i));
i=SetSpeed();
if (i<0)
{
- DPRINTF((DBG_INF,"SBPCD: DiskInfo: second SetSpeed returns %d\n", i));
- return (i);
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: SetSpeed returns %d\n", i));
+ continue;
}
- }
- i=xx_ModeSense();
- if (i<0)
- {
- DPRINTF((DBG_INF,"SBPCD: DiskInfo: first xx_ModeSense returns %d\n", i));
i=xx_ModeSense();
if (i<0)
{
- DPRINTF((DBG_INF,"SBPCD: DiskInfo: second xx_ModeSense returns %d\n", i));
- return (i);
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: xx_ModeSense returns %d\n", i));
+ continue;
}
- return (i);
- }
- i=xx_ReadCapacity();
- if (i<0)
- {
- DPRINTF((DBG_INF,"SBPCD: DiskInfo: first ReadCapacity returns %d\n", i));
i=xx_ReadCapacity();
- if (i<0)
- {
- DPRINTF((DBG_INF,"SBPCD: DiskInfo: second ReadCapacity returns %d\n", i));
- return (i);
- }
- return (i);
+ if (i>=0) break;
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: ReadCapacity #%d returns %d\n", j, i));
+ i=DriveReset();
}
+ if (j==LOOP_COUNT) return (-2); /* give up */
+
i=xx_ReadTocDescr();
if (i<0)
{
/*
* ioctl support, adopted from scsi/sr_ioctl.c and mcd.c
*/
-static int sbpcd_ioctl(struct inode *inode,struct file *file,
- u_int cmd, u_long arg)
+static int SBPCD_IOCTL(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg)
{
int i, st;
DriveStruct[d].mode=READ_M1;
return (0);
- case CDROMREADMODE2:
+ case CDROMREADMODE2: /* not useable at the moment */
DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE2 requested.\n"));
xx_ModeSelect(CD_FRAMESIZE_XA);
xx_ModeSense();
#if READ_AUDIO
case CDROMREADAUDIO:
{ /* start of CDROMREADAUDIO */
-
- int i=0, j=0, frame, block;
- u_int try=0;
- u_long timeout;
- u_char *p;
- u_int data_tries = 0;
- u_int data_waits = 0;
- u_int data_retrying = 0;
- int status_tries;
- int error_flag;
- struct cdrom_aud aud_arg;
-
- error_flag=0;
-
-#if 0
-#define AUD_FRM_SIZ CD_FRAMESIZE_RAW
-#else
-#define AUD_FRM_SIZ CD_FRAMESIZE_XA
-#endif
-
- DPRINTF((DBG_IOC,"SBPCD: read_audio: ioctl: CDROMREADAUDIO requested.\n"));
-
- i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_aud));
- if (i) return (i);
- memcpy_fromfs(&aud_arg, (void *) arg, sizeof(struct cdrom_aud));
- i=verify_area(VERIFY_WRITE, aud_arg.buf, AUD_FRM_SIZ);
- if (i) return (i);
- DPRINTF((DBG_AUD,"SBPCD: read_audio: lba: %d, buffer: %08X\n", aud_arg.lba, aud_arg.buf));
-
- DPRINTF((DBG_AUD,"SBPCD: read_audio: before xx_ReadStatus.\n"));
- for (data_tries=5; data_tries>0; data_tries--)
- {
- DPRINTF((DBG_AUD,"SBPCD: data_tries=%d ...\n", data_tries));
- DriveStruct[d].mode=READ_AU;
- xx_ModeSelect(AUD_FRM_SIZ);
- xx_ModeSense();
-
-
- for (status_tries=3; status_tries > 0; status_tries--)
- {
- flags_cmd_out |= f_respo3;
- xx_ReadStatus();
- if (sbp_status() != 0) break;
- sbp_sleep(1); /* wait a bit, try again */
- }
- if (status_tries == 0)
- {
- DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: failed after 3 tries.\n"));
- continue;
- }
- DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: ok.\n"));
-
-
- block=aud_arg.lba;
- flags_cmd_out = f_putcmd |
- f_respo2 |
- f_ResponseStatus |
- f_obey_p_check;
-
-
-
-
- if (!new_drive)
- {
- flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
- cmd_type=READ_M2;
- drvcmd[0]=0x03; /* "read XA frames" command for old drives */
- drvcmd[1]=(block>>16)&0x000000ff;
- drvcmd[2]=(block>>8)&0x000000ff;
- drvcmd[3]=block&0x000000ff;
- drvcmd[4]=0;
- drvcmd[5]=1; /* # of frames */
- drvcmd[6]=0;
- }
- else /* if new_drive */
- {
- drvcmd[0]=0x10; /* "read frames" command for new drives */
- lba2msf(block,&drvcmd[1]); /* msf-bin format required */
- drvcmd[4]=0;
- drvcmd[5]=0;
- drvcmd[6]=1; /* # of frames */
- }
-
-
-
- DPRINTF((DBG_AUD,"SBPCD: read_audio: before giving \"read\" command.\n"));
- for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
-
- sbp_sleep(0);
-
- DPRINTF((DBG_AUD,"SBPCD: read_audio: after giving \"read\" command.\n"));
- for (frame=1;frame<2 && !error_flag; frame++)
- {
- try=maxtim_data;
- for (timeout=jiffies+900; ; )
- {
- for ( ; try!=0;try--)
- {
- j=inb(CDi_status);
- if (!(j&s_not_data_ready)) break;
- if (!(j&s_not_result_ready)) break;
- if (!new_drive) if (j&s_attention) break;
- }
- if (try != 0 || timeout <= jiffies) break;
- if (data_retrying == 0) data_waits++;
- data_retrying = 1;
- sbp_sleep(1);
- try = 1;
- }
- if (try==0)
- {
- DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status timeout.\n"));
- error_flag++;
- break;
- }
- DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status ok.\n"));
-
- if (j&s_not_data_ready)
- {
- printk("SBPCD: read_audio: sbp_data: DATA_READY timeout.\n");
- error_flag++;
- break;
- }
-
- DPRINTF((DBG_AUD,"SBPCD: read_audio: before reading data.\n"));
- CLEAR_TIMER;
- error_flag=0;
- p = DriveStruct[d].aud_buf;
- if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
- READ_DATA(CDi_data, p, AUD_FRM_SIZ);
- if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
- data_retrying = 0;
- }
- DPRINTF((DBG_AUD,"SBPCD: read_audio: after reading data.\n"));
- if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
- {
- DPRINTF((DBG_AUD,"SBPCD: read_audio: read aborted by drive\n"));
+ int i=0, j=0, frame, block;
+ u_int try=0;
+ u_long timeout;
+ u_char *p;
+ u_int data_tries = 0;
+ u_int data_waits = 0;
+ u_int data_retrying = 0;
+ int status_tries;
+ int error_flag;
+
+ error_flag=0;
+
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADAUDIO requested.\n"));
+
+ i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio));
+ if (i) return (i);
+ memcpy_fromfs(&read_audio, (void *) arg, sizeof(struct cdrom_read_audio));
+ i=verify_area(VERIFY_WRITE, read_audio.buf, CD_FRAMESIZE_RAW);
+ if (i) return (i);
+
+ if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */
+ block=msf2blk(read_audio.addr.lba);
+ else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */
+ block=read_audio.addr.lba;
+ else return (-EINVAL);
+ if (read_audio.nframes!=1) return (-EINVAL);
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: lba: %d, msf: %06X\n",
+ block, blk2msf(block)));
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: before xx_ReadStatus.\n"));
+ for (data_tries=5; data_tries>0; data_tries--)
+ {
+ DPRINTF((DBG_AUD,"SBPCD: data_tries=%d ...\n", data_tries));
+ DriveStruct[d].mode=READ_AU;
+ xx_ModeSelect(CD_FRAMESIZE_RAW);
+ xx_ModeSense();
+ for (status_tries=3; status_tries > 0; status_tries--)
+ {
+ flags_cmd_out |= f_respo3;
+ xx_ReadStatus();
+ if (sbp_status() != 0) break;
+ sbp_sleep(1); /* wait a bit, try again */
+ }
+ if (status_tries == 0)
+ {
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: failed after 3 tries.\n"));
+ continue;
+ }
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: ok.\n"));
+
+ flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check;
+ if (!new_drive)
+ {
+ flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
+ cmd_type=READ_M2;
+ drvcmd[0]=0x03; /* "read XA frames" command for old drives */
+ drvcmd[1]=(block>>16)&0x000000ff;
+ drvcmd[2]=(block>>8)&0x000000ff;
+ drvcmd[3]=block&0x000000ff;
+ drvcmd[4]=0;
+ drvcmd[5]=1; /* # of frames */
+ drvcmd[6]=0;
+ }
+ else /* if new_drive */
+ {
+ drvcmd[0]=0x10; /* "read frames" command for new drives */
+ lba2msf(block,&drvcmd[1]); /* msf-bin format required */
+ drvcmd[4]=0;
+ drvcmd[5]=0;
+ drvcmd[6]=1; /* # of frames */
+ }
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: before giving \"read\" command.\n"));
+ for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
+ sbp_sleep(0);
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: after giving \"read\" command.\n"));
+ for (frame=1;frame<2 && !error_flag; frame++)
+ {
+ try=maxtim_data;
+ for (timeout=jiffies+900; ; )
+ {
+ for ( ; try!=0;try--)
+ {
+ j=inb(CDi_status);
+ if (!(j&s_not_data_ready)) break;
+ if (!(j&s_not_result_ready)) break;
+ if (!new_drive) if (j&s_attention) break;
+ }
+ if (try != 0 || timeout <= jiffies) break;
+ if (data_retrying == 0) data_waits++;
+ data_retrying = 1;
+ sbp_sleep(1);
+ try = 1;
+ }
+ if (try==0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status timeout.\n"));
+ error_flag++;
+ break;
+ }
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_data: CDi_status ok.\n"));
+ if (j&s_not_data_ready)
+ {
+ printk("SBPCD: read_audio: sbp_data: DATA_READY timeout.\n");
+ error_flag++;
+ break;
+ }
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: before reading data.\n"));
+ CLEAR_TIMER;
+ error_flag=0;
+ p = DriveStruct[d].aud_buf;
+ if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
+ READ_DATA(CDi_data, p, CD_FRAMESIZE_RAW);
+ if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
+ data_retrying = 0;
+ }
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: after reading data.\n"));
+ if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
+ {
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: read aborted by drive\n"));
#if 0000
- i=DriveReset(); /* ugly fix to prevent a hang */
+ i=DriveReset(); /* ugly fix to prevent a hang */
#endif 0000
- continue;
- }
-
- if (!new_drive)
- {
- i=maxtim_data;
- for (timeout=jiffies+900; timeout > jiffies; timeout--)
- {
- for ( ;i!=0;i--)
- {
- j=inb(CDi_status);
- if (!(j&s_not_data_ready)) break;
- if (!(j&s_not_result_ready)) break;
- if (j&s_attention) break;
- }
- if (i != 0 || timeout <= jiffies) break;
- sbp_sleep(0);
- i = 1;
- }
- if (i==0) { DPRINTF((DBG_AUD,"SBPCD: read_audio: STATUS TIMEOUT AFTER READ")); }
- if (!(j&s_attention))
- {
- DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n"));
- i=DriveReset(); /* ugly fix to prevent a hang */
+ continue;
+ }
+ if (!new_drive)
+ {
+ i=maxtim_data;
+ for (timeout=jiffies+900; timeout > jiffies; timeout--)
+ {
+ for ( ;i!=0;i--)
+ {
+ j=inb(CDi_status);
+ if (!(j&s_not_data_ready)) break;
+ if (!(j&s_not_result_ready)) break;
+ if (j&s_attention) break;
+ }
+ if (i != 0 || timeout <= jiffies) break;
+ sbp_sleep(0);
+ i = 1;
+ }
+ if (i==0) { DPRINTF((DBG_AUD,"SBPCD: read_audio: STATUS TIMEOUT AFTER READ")); }
+ if (!(j&s_attention))
+ {
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n"));
+ i=DriveReset(); /* ugly fix to prevent a hang */
continue;
- }
- }
-
- do
- {
- if (!new_drive) xx_ReadStatus();
- i=ResponseStatus(); /* builds status_byte, returns orig. status (old) or faked p_success_old (new) */
- if (i<0) { DPRINTF((DBG_AUD,
- "SBPCD: read_audio: xx_ReadStatus error after read: %02X\n",
- DriveStruct[d].status_byte));
- continue; /* FIXME */
- }
- }
- while ((!new_drive)&&(!st_check)&&(!(i&p_success_old)));
- if (st_check)
- {
- i=xx_ReadError();
- DPRINTF((DBG_AUD,"SBPCD: read_audio: xx_ReadError was necessary after read: %02X\n",i));
- continue;
- }
- memcpy_tofs((u_char *) aud_arg.buf,
- (u_char *) DriveStruct[d].aud_buf, AUD_FRM_SIZ);
- DPRINTF((DBG_AUD,"SBPCD: read_audio: memcpy_tofs done.\n"));
- break;
- }
- xx_ModeSelect(CD_FRAMESIZE);
- xx_ModeSense();
- DriveStruct[d].mode=READ_M1;
-
-
- if (data_tries == 0)
- {
- DPRINTF((DBG_AUD,"SBPCD: read_audio: failed after 5 tries.\n"));
- return (-8);
- }
- DPRINTF((DBG_AUD,"SBPCD: read_audio: successful return.\n"));
- return (0);
- } /* end of CDROMREADAUDIO */
+ }
+ }
+ do
+ {
+ if (!new_drive) xx_ReadStatus();
+ i=ResponseStatus(); /* builds status_byte, returns orig. status (old) or faked p_success_old (new) */
+ if (i<0) { DPRINTF((DBG_AUD,
+ "SBPCD: read_audio: xx_ReadStatus error after read: %02X\n",
+ DriveStruct[d].status_byte));
+ continue; /* FIXME */
+ }
+ }
+ while ((!new_drive)&&(!st_check)&&(!(i&p_success_old)));
+ if (st_check)
+ {
+ i=xx_ReadError();
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: xx_ReadError was necessary after read: %02X\n",i));
+ continue;
+ }
+ memcpy_tofs((u_char *) read_audio.buf,
+ (u_char *) DriveStruct[d].aud_buf, CD_FRAMESIZE_RAW);
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: memcpy_tofs done.\n"));
+ break;
+ }
+ xx_ModeSelect(CD_FRAMESIZE);
+ xx_ModeSense();
+ DriveStruct[d].mode=READ_M1;
+ if (data_tries == 0)
+ {
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: failed after 5 tries.\n"));
+ return (-8);
+ }
+ DPRINTF((DBG_AUD,"SBPCD: read_audio: successful return.\n"));
+ return (0);
+ } /* end of CDROMREADAUDIO */
#endif READ_AUDIO
-
-
-
case BLKRASET:
if(!suser()) return -EACCES;
if(!inode->i_rdev) return -EINVAL;
/*
* I/O request routine, called from Linux kernel.
*/
-static void do_sbpcd_request(void)
+static void DO_SBPCD_REQUEST(void)
{
u_int block;
int dev;
block=DriveStruct[d].lba_multi+block;
}
#else
- if ( (block==166) && (DriveStruct[d].f_multisession) && (multisession_valid) )
+ if ( (block==CD_BLOCK_OFFSET+16) && (DriveStruct[d].f_multisession) && (multisession_valid) )
{
DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
blk2msf(DriveStruct[d].lba_multi+16),
/*
* Open the device special file. Check that a disk is in. Read TOC.
*/
-int sbpcd_open(struct inode *ip, struct file *fp)
+int SBPCD_OPEN(struct inode *ip, struct file *fp)
{
int i;
*/
DPRINTF((DBG_LCK,"SBPCD: open_count: %d -> %d\n",
DriveStruct[d].open_count,DriveStruct[d].open_count+1));
- if (++DriveStruct[d].open_count==1) yy_LockDoor(1);
-
+ if (++DriveStruct[d].open_count==1)
+ {
+ do
+ i=yy_LockDoor(1);
+ while (i!=0);
+ }
if (!st_spinning) xx_SpinUp();
i=DiskInfo();
/*
* On close, we flush all sbp blocks from the buffer cache.
*/
-static void sbpcd_release(struct inode * ip, struct file * file)
+static void SBPCD_RELEASE(struct inode * ip, struct file * file)
{
int i;
block_write, /* write - general block-dev write */
NULL, /* readdir - bad */
NULL, /* select */
- sbpcd_ioctl, /* ioctl */
+ SBPCD_IOCTL_F, /* ioctl */
NULL, /* mmap */
- sbpcd_open, /* open */
- sbpcd_release, /* release */
+ SBPCD_OPEN_F, /* open */
+ SBPCD_RELEASE_F, /* release */
NULL, /* fsync */
NULL /* fasync */
};
* not the soundcard base address.
*
*/
-void sbpcd_setup(char *s, int *p)
+void SBPCD_SETUP(char *s, int *p)
{
DPRINTF((DBG_INI,"SBPCD: sbpcd_setup called with %04X,%s\n",p[1], s));
sbpro_type=0;
* -> interface type "Matsushita/Panasonic" (not Sony or Mitsumi)
* -> I/O base address (0x320, 0x330, 0x340, 0x350)
*/
-int config_spea(void)
+static int config_spea(void)
{
int n_ports=0x10; /* 2:0x00, 8:0x10, 16:0x20, 32:0x30 */
int irq_number=0; /* 2:0x01, 7:0x03, 12:0x05, 15:0x07, OFF:0x00 */
i=inb(SPEA_REG_1);
if (i!=0x0F)
{
- DPRINTF((DBG_INF,"SBPCD: no SPEA interface at %04X present.\n",
+ DPRINTF((DBG_SEQ,"SBPCD: no SPEA interface at %04X present.\n",
sbpcd_ioaddr));
return (-1); /* no interface found */
}
OUT(SPEA_REG_2,i);
sbpro_type = 0; /* acts like a LaserMate interface now */
+ DPRINTF((DBG_SEQ,"SBPCD: found SPEA interface at %04X.\n",
+ sbpcd_ioaddr));
return (0);
}
/*==========================================================================*/
/*
* Test for presence of drive and initialize it. Called at boot time.
*/
-u_long sbpcd_init(u_long mem_start, u_long mem_end)
+unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
{
int i=0, j=0;
int addr[2]={1, CDROM_PORT};
int port_index;
+ sti(); /* necessary, has consequences for other drivers' init routines */
+
DPRINTF((DBG_INF,"SBPCD version %s\n", VERSION));
DPRINTF((DBG_INF,"SBPCD: Looking for a SoundBlaster/Matsushita CD-ROM drive\n"));
DPRINTF((DBG_WRN,"SBPCD: with your REAL address.\n"));
DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =\n"));
DPRINTF((DBG_WRN,"SBPCD: \n"));
- sti(); /* to avoid possible "printk" bug */
autoprobe[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
autoprobe[1]=sbpro_type; /* possibly changed by kernel command line */
{
addr[1]=autoprobe[port_index];
if (check_region(addr[1],4)) continue;
- DPRINTF((DBG_INI,"SBPCD: check_region done.\n"));
+ DPRINTF((DBG_INI,"SBPCD: check_region: free.\n"));
if (autoprobe[port_index+1]==0) type=str_lm;
else if (autoprobe[port_index+1]==1) type=str_sb;
else type=str_sp;
- sbpcd_setup(type, addr);
+ SBPCD_SETUP(type, addr);
DPRINTF((DBG_INF,"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.\n",
type, CDo_command));
DPRINTF((DBG_INF,"SBPCD: - "));
- sti(); /* to avoid possible "printk" bug */
if (autoprobe[port_index+1]==2)
{
i=config_spea();
- if (i<0) continue;
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"\n"));
+ continue;
+ }
}
i=check_drives();
DPRINTF((DBG_INI,"SBPCD: check_drives done.\n"));
- sti(); /* to avoid possible "printk" bug */
if (i>=0) break; /* drive found */
DPRINTF((DBG_INF,"\n"));
- sti(); /* to avoid possible "printk" bug */
} /* end of cycling through the set of possible I/O port addresses */
if (ndrives==0)
{
printk("SBPCD: No drive found.\n");
- sti();
+#if PRINTK_BUG
+ sti(); /* to avoid possible "printk" bug */
+#endif
return (mem_start);
}
if (port_index>0)
{
printk("SBPCD: You should configure sbpcd.h for your hardware.\n");
- sti();
+#if PRINTK_BUG
+ sti(); /* to avoid possible "printk" bug */
+#endif
}
printk("SBPCD: %d %s CD-ROM drive(s) at 0x%04X.\n",
ndrives, type, CDo_command);
+#if PRINTK_BUG
sti(); /* to avoid possible "printk" bug */
+#endif
check_datarate();
DPRINTF((DBG_INI,"SBPCD: check_datarate done.\n"));
- sti(); /* to avoid possible "printk" bug */
for (j=0;j<NR_SBPCD;j++)
{
{
i=xx_ReadError();
DPRINTF((DBG_INI,"SBPCD: init: xx_ReadError returns %d\n",i));
- sti(); /* to avoid possible "printk" bug */
}
}
DPRINTF((DBG_INI,"SBPCD: init: first GetStatus: %d\n",i));
- sti(); /* to avoid possible "printk" bug */
if (DriveStruct[d].error_byte==aud_12)
{
do { i=GetStatus();
DPRINTF((DBG_INI,"SBPCD: init: second GetStatus: %02X\n",i));
- sti(); /* to avoid possible "printk" bug */
if (i<0) break;
if (!st_caddy_in) break;
}
if (register_blkdev(MAJOR_NR, "sbpcd", &sbpcd_fops) != 0)
{
printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n", MAJOR_NR);
+#if PRINTK_BUG
sti(); /* to avoid possible "printk" bug */
+#endif
return (mem_start);
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blksize_size[MAJOR_NR]=sbpcd_blocksizes;
DPRINTF((DBG_INF,"SBPCD: init done.\n"));
- sti(); /* to avoid possible "printk" bug */
return (mem_start);
}
/*==========================================================================*/
* used externally (isofs/inode.c, fs/buffer.c)
* Currently disabled (has to get "synchronized").
*/
-int check_sbpcd_media_change(int full_dev, int unused_minor)
+int SBPCD_MEDIA_CHANGE(int full_dev, int unused_minor)
{
int st;
return 1;
if (tty_hung_up_p(file))
return 1;
- if (!tty->read_wait)
- tty->minimum_to_wake = MIN_CHAR(tty) ?
- MIN_CHAR(tty) : 1;
+ if (!tty->read_wait) {
+ if (MIN_CHAR(tty) && !TIME_CHAR(tty))
+ tty->minimum_to_wake = MIN_CHAR(tty);
+ else
+ tty->minimum_to_wake = 1;
+ }
select_wait(&tty->read_wait, wait);
return 0;
case SEL_OUT:
+++ /dev/null
-static char *version =
- "d_link.c: $Revision: 0.32 $, Bjorn Ekwall (bj0rn@blox.se)\n";
-/*
- * d_link.c
- *
- * Linux driver for the D-Link DE-600 Ethernet pocket adapter.
- *
- * Portions (C) Copyright 1993 by Bjorn Ekwall
- * The Author may be reached as bj0rn@blox.se
- *
- * Based on adapter information gathered from DE600.ASM by D-Link Inc.,
- * as included on disk C in the v.2.11 of PC/TCP from FTP Software.
- * For DE600.asm:
- * Portions (C) Copyright 1990 D-Link, Inc.
- * Copyright, 1988-1992, Russell Nelson, Crynwr Software
- *
- * Adapted to the sample network driver core for linux,
- * written by: Donald Becker <becker@super.org>
- * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
- *
- * compile-command:
- * "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer \
- * -m486 -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG -S d_link.c
- *
- **************************************************************/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- **************************************************************/
-/* Add another "; SLOW_DOWN_IO" here if your adapter won't work OK: */
-#define D_LINK_SLOW_DOWN SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO
-
- /*
- * If you still have trouble reading/writing to the adapter,
- * modify the following "#define": (see <asm/io.h> for more info)
-#define REALLY_SLOW_IO
- */
-#define SLOW_IO_BY_JUMPING /* Looks "better" than dummy write to port 0x80 :-) */
-
-/*
- * For fix to TCP "slowdown", take a look at the "#define D_LINK_MAX_WINDOW"
- * near the end of the file...
- */
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifdef D_LINK_DEBUG
-#define PRINTK(x) if (d_link_debug >= 2) printk x
-#else
-#define D_LINK_DEBUG 0
-#define PRINTK(x) /**/
-#endif
-static unsigned int d_link_debug = D_LINK_DEBUG;
-\f
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <netinet/in.h>
-#include <linux/ptrace.h>
-#include <asm/system.h>
-#include <errno.h>
-
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#define netstats enet_statistics
-
-/**************************************************
- * *
- * Definition of D-Link Ethernet Pocket adapter *
- * *
- **************************************************/
-/*
- * D-Link Ethernet pocket adapter ports
- */
-/*
- * OK, so I'm cheating, but there are an awful lot of
- * reads and writes in order to get anything in and out
- * of the DE-600 with 4 bits at a time in the parallel port,
- * so every saved instruction really helps :-)
- *
- * That is, I don't care what the device struct says
- * but hope that Space.c will keep the rest of the drivers happy.
- */
-#ifndef D_LINK_IO
-#define D_LINK_IO 0x378
-#endif
-
-#define DATA_PORT (D_LINK_IO)
-#define STATUS_PORT (D_LINK_IO + 1)
-#define COMMAND_PORT (D_LINK_IO + 2)
-
-#ifndef D_LINK_IRQ
-#define D_LINK_IRQ 7
-#endif
-/*
- * It really should look like this, and autoprobing as well...
- *
-#define DATA_PORT (dev->base_addr + 0)
-#define STATUS_PORT (dev->base_addr + 1)
-#define COMMAND_PORT (dev->base_addr + 2)
-#define D_LINK_IRQ dev->irq
- */
-
-/*
- * D-Link COMMAND_PORT commands
- */
-#define SELECT_NIC 0x04 /* select Network Interface Card */
-#define SELECT_PRN 0x1c /* select Printer */
-#define NML_PRN 0xec /* normal Printer situation */
-#define IRQEN 0x10 /* enable IRQ line */
-
-/*
- * D-Link STATUS_PORT
- */
-#define RX_BUSY 0x80
-#define RX_GOOD 0x40
-#define TX_FAILED16 0x10
-#define TX_BUSY 0x08
-
-/*
- * D-Link DATA_PORT commands
- * command in low 4 bits
- * data in high 4 bits
- * select current data nibble with HI_NIBBLE bit
- */
-#define WRITE_DATA 0x00 /* write memory */
-#define READ_DATA 0x01 /* read memory */
-#define STATUS 0x02 /* read status register */
-#define COMMAND 0x03 /* write command register (see COMMAND below) */
-#define NULL_COMMAND 0x04 /* null command */
-#define RX_LEN 0x05 /* read received packet length */
-#define TX_ADDR 0x06 /* set adapter transmit memory address */
-#define RW_ADDR 0x07 /* set adapter read/write memory address */
-#define HI_NIBBLE 0x08 /* read/write the high nibble of data,
- or-ed with rest of command */
-
-/*
- * command register, accessed through DATA_PORT with low bits = COMMAND
- */
-#define RX_ALL 0x01 /* PROMISCIOUS */
-#define RX_BP 0x02 /* default: BROADCAST & PHYSICAL ADRESS */
-#define RX_MBP 0x03 /* MULTICAST, BROADCAST & PHYSICAL ADRESS */
-
-#define TX_ENABLE 0x04 /* bit 2 */
-#define RX_ENABLE 0x08 /* bit 3 */
-
-#define RESET 0x80 /* set bit 7 high */
-#define STOP_RESET 0x00 /* set bit 7 low */
-
-/*
- * data to command register
- * (high 4 bits in write to DATA_PORT)
- */
-#define RX_PAGE2_SELECT 0x10 /* bit 4, only 2 pages to select */
-#define RX_BASE_PAGE 0x20 /* bit 5, always set when specifying RX_ADDR */
-#define FLIP_IRQ 0x40 /* bit 6 */
-
-/*
- * D-Link adapter internal memory:
- *
- * 0-2K 1:st transmit page (send from pointer up to 2K)
- * 2-4K 2:nd transmit page (send from pointer up to 4K)
- *
- * 4-6K 1:st receive page (data from 4K upwards)
- * 6-8K 2:nd receive page (data from 6K upwards)
- *
- * 8K+ Adapter ROM (contains magic code and last 3 bytes of Ethernet address)
- */
-#define MEM_2K 0x0800 /* 2048 */
-#define MEM_4K 0x1000 /* 4096 */
-#define MEM_6K 0x1800 /* 6144 */
-#define NODE_ADDRESS 0x2000 /* 8192 */
-
-#define RUNT 60 /* Too small Ethernet packet */
-
-/**************************************************
- * *
- * End of definition *
- * *
- **************************************************/
-
-/*
- * Index to functions, as function prototypes.
- */
-#if 0
-/* For tricking tcp.c to announce a small max window (max 2 fast packets please :-) */
-static unsigned long d_link_rspace(struct sock *sk);
-#endif
-
-/* Routines used internally. (See "convenience macros") */
-static int d_link_read_status(struct device *dev);
-static unsigned char d_link_read_byte(unsigned char type, struct device *dev);
-
-/* Put in the device structure. */
-static int d_link_open(struct device *dev);
-static int d_link_close(struct device *dev);
-static struct netstats *get_stats(struct device *dev);
-static int d_link_start_xmit(struct sk_buff *skb, struct device *dev);
-
-/* Dispatch from interrupts. */
-static void d_link_interrupt(int reg_ptr);
-static int d_link_tx_intr(struct device *dev, int irq_status);
-static void d_link_rx_intr(struct device *dev);
-
-/* Initialization */
-static void trigger_interrupt(struct device *dev);
-int d_link_init(struct device *dev);
-static void adapter_init(struct device *dev);
-
-/*
- * D-Link driver variables:
- */
-extern struct device *irq2dev_map[16];
-static volatile int rx_page = 0;
-
-#define TX_PAGES 2
-static volatile int tx_fifo[TX_PAGES];
-static volatile int tx_fifo_in = 0;
-static volatile int tx_fifo_out = 0;
-static volatile int free_tx_pages = TX_PAGES;
-
-/*
- * Convenience macros/functions for D-Link adapter
- */
-
-#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); D_LINK_SLOW_DOWN
-#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); D_LINK_SLOW_DOWN
-
-/* Thanks for hints from Mark Burton <markb@ordern.demon.co.uk> */
-#define d_link_put_byte(data) ( \
- outb_p(((data) << 4) | WRITE_DATA , DATA_PORT), \
- outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT))
-
-/*
- * The first two outb_p()'s below could perhaps be deleted if there
- * would be more delay in the last two. Not certain about it yet...
- */
-#define d_link_put_command(cmd) ( \
- outb_p(( rx_page << 4) | COMMAND , DATA_PORT), \
- outb_p(( rx_page & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \
- outb_p(((rx_page | cmd) << 4) | COMMAND , DATA_PORT), \
- outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT))
-
-#define d_link_setup_address(addr,type) ( \
- outb_p((((addr) << 4) & 0xf0) | type , DATA_PORT), \
- outb_p(( (addr) & 0xf0) | type | HI_NIBBLE, DATA_PORT), \
- outb_p((((addr) >> 4) & 0xf0) | type , DATA_PORT), \
- outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT))
-
-#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K))
-
-/* Flip bit, only 2 pages */
-#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT)
-
-#define tx_page_adr(a) (((a) + 1) * MEM_2K)
-
-static inline int
-d_link_read_status(struct device *dev)
-{
- int status;
-
- outb_p(STATUS, DATA_PORT);
- status = inb(STATUS_PORT);
- outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT);
-
- return status;
-}
-
-static inline unsigned char
-d_link_read_byte(unsigned char type, struct device *dev) { /* dev used by macros */
- unsigned char lo;
-
- (void)outb_p((type), DATA_PORT);
- lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
- (void)outb_p((type) | HI_NIBBLE, DATA_PORT);
- return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo;
-}
-\f
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * after booting when 'ifconfig <dev->name> $IP_ADDR' is run (in rc.inet1).
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- */
-static int
-d_link_open(struct device *dev)
-{
- extern struct proto tcp_prot;
-
- if (request_irq(D_LINK_IRQ, d_link_interrupt)) {
- printk ("%s: unable to get IRQ %d\n", dev->name, D_LINK_IRQ);
- return 1;
- }
- irq2dev_map[D_LINK_IRQ] = dev;
-
- adapter_init(dev);
-
- /*
- * Yes, I know!
- * This is really not nice, but since a machine that uses DE-600
- * rarely uses any other TCP/IP connection device simultaneously,
- * this hack shouldn't really slow anything up.
- * (I don't know about slip though... but it won't break it)
- *
- * This fix is better than changing in tcp.h IMHO
- */
-#if 0
- tcp_prot.rspace = d_link_rspace; /* was: sock_rspace */
-#endif
-
-
- return 0;
-}
-
-/*
- * The inverse routine to d_link_open().
- */
-static int
-d_link_close(struct device *dev)
-{
- select_nic();
- rx_page = 0;
- d_link_put_command(RESET);
- d_link_put_command(STOP_RESET);
- d_link_put_command(0);
- select_prn();
-
- free_irq(D_LINK_IRQ);
- irq2dev_map[D_LINK_IRQ] = NULL;
- dev->start = 0;
-#if 0
- tcp_prot.rspace = sock_rspace; /* see comment above! */
-#endif
- return 0;
-}
-
-static struct netstats *
-get_stats(struct device *dev)
-{
- return (struct netstats *)(dev->priv);
-}
-
-static inline void
-trigger_interrupt(struct device *dev)
-{
- d_link_put_command(FLIP_IRQ);
- select_prn();
- D_LINK_SLOW_DOWN;
- select_nic();
- d_link_put_command(0);
-}
-
-/*
- * Copy a buffer to the adapter transmit page memory.
- * Start sending.
- */
-static int
-d_link_start_xmit(struct sk_buff *skb, struct device *dev)
-{
- int transmit_from;
- int len;
- int tickssofar;
- unsigned char *buffer = skb->data;
-
- /*
- * If some higher layer thinks we've missed a
- * tx-done interrupt we are passed NULL.
- * Caution: dev_tint() handles the cli()/sti() itself.
- */
-
- if (skb == NULL) {
- dev_tint(dev);
- return 0;
- }
-
- if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */
- tickssofar = jiffies - dev->trans_start;
-
- if (tickssofar < 5)
- return 1;
-
- /* else */
- printk("%s: transmit timed out (%d), %s?\n",
- dev->name,
- tickssofar,
- "network cable problem"
- );
- /* Restart the adapter. */
- adapter_init(dev);
- }
-
- /* Start real output */
- PRINTK(("d_link_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages));
-
- if ((len = skb->len) < RUNT)
- len = RUNT;
-
- cli();
- select_nic();
-
- tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
- tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */
-
- d_link_setup_address(transmit_from, RW_ADDR);
- for ( ; len > 0; --len, ++buffer)
- d_link_put_byte(*buffer);
-
- if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
- dev->trans_start = jiffies;
- dev->tbusy = 0; /* allow more packets into adapter */
- /* Send page and generate an interrupt */
- d_link_setup_address(transmit_from, TX_ADDR);
- d_link_put_command(TX_ENABLE);
- }
- else {
- dev->tbusy = !free_tx_pages;
- select_prn();
- }
-
- sti(); /* interrupts back on */
-
- if (skb->free)
- kfree_skb (skb, FREE_WRITE);
-
- return 0;
-}
-\f
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-static void
-d_link_interrupt(int reg_ptr)
-{
- int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
- struct device *dev = irq2dev_map[irq];
- unsigned char irq_status;
- int retrig = 0;
- int boguscount = 0;
-
- /* This might just as well be deleted now, no crummy drivers present :-) */
- if ((dev == NULL) || (dev->start == 0) || (D_LINK_IRQ != irq)) {
- printk("%s: bogus interrupt %d\n", dev?dev->name:"DE-600", irq);
- return;
- }
-
- dev->interrupt = 1;
- select_nic();
- irq_status = d_link_read_status(dev);
-
- do {
- PRINTK(("d_link_interrupt (%2.2X)\n", irq_status));
-
- if (irq_status & RX_GOOD)
- d_link_rx_intr(dev);
- else if (!(irq_status & RX_BUSY))
- d_link_put_command(RX_ENABLE);
-
- /* Any transmission in progress? */
- if (free_tx_pages < TX_PAGES)
- retrig = d_link_tx_intr(dev, irq_status);
- else
- retrig = 0;
-
- irq_status = d_link_read_status(dev);
- } while ( (irq_status & RX_GOOD) || ((++boguscount < 10) && retrig) );
- /*
- * Yeah, it _looks_ like busy waiting, smells like busy waiting
- * and I know it's not PC, but please, it will only occur once
- * in a while and then only for a loop or so (< 1ms for sure!)
- */
-
- /* Enable adapter interrupts */
- dev->interrupt = 0;
- select_prn();
-
- if (retrig)
- trigger_interrupt(dev);
-
- sti();
- return;
-}
-
-static int
-d_link_tx_intr(struct device *dev, int irq_status)
-{
- /*
- * Returns 1 if tx still not done
- */
-
- mark_bh(INET_BH);
- /* Check if current transmission is done yet */
- if (irq_status & TX_BUSY)
- return 1; /* tx not done, try again */
-
- /* else */
- /* If last transmission OK then bump fifo index */
- if (!(irq_status & TX_FAILED16)) {
- tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
- ++free_tx_pages;
- ((struct netstats *)(dev->priv))->tx_packets++;
- dev->tbusy = 0;
- }
-
- /* More to send, or resend last packet? */
- if ((free_tx_pages < TX_PAGES) || (irq_status & TX_FAILED16)) {
- dev->trans_start = jiffies;
- d_link_setup_address(tx_fifo[tx_fifo_out], TX_ADDR);
- d_link_put_command(TX_ENABLE);
- return 1;
- }
- /* else */
-
- return 0;
-}
-
-/*
- * We have a good packet, get it out of the adapter.
- */
-static void
-d_link_rx_intr(struct device *dev)
-{
- struct sk_buff *skb;
- int i;
- int read_from;
- int size;
- register unsigned char *buffer;
-
- cli();
- /* Get size of received packet */
- size = d_link_read_byte(RX_LEN, dev); /* low byte */
- size += (d_link_read_byte(RX_LEN, dev) << 8); /* high byte */
- size -= 4; /* Ignore trailing 4 CRC-bytes */
-
- /* Tell adapter where to store next incoming packet, enable receiver */
- read_from = rx_page_adr();
- next_rx_page();
- d_link_put_command(RX_ENABLE);
- sti();
-
- if ((size < 32) || (size > 1535))
- printk("%s: Bogus packet size %d.\n", dev->name, size);
-
- skb = alloc_skb(size, GFP_ATOMIC);
- sti();
- if (skb == NULL) {
- printk("%s: Couldn't allocate a sk_buff of size %d.\n",
- dev->name, size);
- return;
- }
- /* else */
-
- skb->lock = 0;
- /* 'skb->data' points to the start of sk_buff data area. */
- buffer = skb->data;
-
- /* copy the packet into the buffer */
- d_link_setup_address(read_from, RW_ADDR);
- for (i = size; i > 0; --i, ++buffer)
- *buffer = d_link_read_byte(READ_DATA, dev);
-
- ((struct netstats *)(dev->priv))->rx_packets++; /* count all receives */
-
- if (dev_rint((unsigned char *)skb, size, IN_SKBUFF, dev))
- printk("%s: receive buffers full.\n", dev->name);
- /*
- * If any worth-while packets have been received, dev_rint()
- * has done a mark_bh(INET_BH) for us and will work on them
- * when we get to the bottom-half routine.
- */
-}
-
-int
-d_link_init(struct device *dev)
-{
- int i;
-
- printk("%s: D-Link DE-600 pocket adapter", dev->name);
- /* Alpha testers must have the version number to report bugs. */
- if (d_link_debug > 1)
- printk(version);
-
- /* probe for adapter */
- rx_page = 0;
- select_nic();
- (void)d_link_read_status(dev);
- d_link_put_command(RESET);
- d_link_put_command(STOP_RESET);
- if (d_link_read_status(dev) & 0xf0) {
- printk(": not at I/O %#3x.\n", DATA_PORT);
- return ENODEV;
- }
-
- /*
- * Maybe we found one,
- * have to check if it is a D-Link DE-600 adapter...
- */
-
- /* Get the adapter ethernet address from the ROM */
- d_link_setup_address(NODE_ADDRESS, RW_ADDR);
- for (i = 0; i < ETH_ALEN; i++) {
- dev->dev_addr[i] = d_link_read_byte(READ_DATA, dev);
- dev->broadcast[i] = 0xff;
- }
-
- /* Check magic code */
- if ((dev->dev_addr[1] == 0xde) && (dev->dev_addr[2] == 0x15)) {
- /* OK, install real address */
- dev->dev_addr[0] = 0x00;
- dev->dev_addr[1] = 0x80;
- dev->dev_addr[2] = 0xc8;
- dev->dev_addr[3] &= 0x0f;
- dev->dev_addr[3] |= 0x70;
- } else {
- printk(" not identified in the printer port\n");
- return ENODEV;
- }
-
- printk(", Ethernet Address: %2.2X", dev->dev_addr[0]);
- for (i = 1; i < ETH_ALEN; i++)
- printk(":%2.2X",dev->dev_addr[i]);
- printk("\n");
-
- /* Initialize the device structure. */
- dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct netstats));
- dev->get_stats = get_stats;
-
- dev->open = d_link_open;
- dev->stop = d_link_close;
- dev->hard_start_xmit = &d_link_start_xmit;
-
- ether_setup(dev);
-
- select_prn();
- return 0;
-}
-
-static void
-adapter_init(struct device *dev)
-{
- int i;
-
- cli();
- dev->tbusy = 0; /* Transmit busy... */
- dev->interrupt = 0;
- dev->start = 1;
-
- select_nic();
- rx_page = 0; /* used by RESET */
- d_link_put_command(RESET);
- d_link_put_command(STOP_RESET);
-
- tx_fifo_in = 0;
- tx_fifo_out = 0;
- free_tx_pages = TX_PAGES;
-
- /* set the ether address. */
- d_link_setup_address(NODE_ADDRESS, RW_ADDR);
- for (i = 0; i < ETH_ALEN; i++)
- d_link_put_byte(dev->dev_addr[i]);
-
- /* where to start saving incoming packets */
- rx_page = RX_BP | RX_BASE_PAGE;
- d_link_setup_address(MEM_4K, RW_ADDR);
- /* Enable receiver */
- d_link_put_command(RX_ENABLE);
- select_prn();
- sti();
-}
-
-#if 0
-/*
- * The new router code (coming soon 8-) ) will fix this properly.
- */
-#define D_LINK_MIN_WINDOW 1024
-#define D_LINK_MAX_WINDOW 2048
-#define D_LINK_TCP_WINDOW_DIFF 1024
-/*
- * Copied from sock.c
- *
- * Sets a lower max receive window in order to achieve <= 2
- * packets arriving at the adapter in fast succession.
- * (No way that a DE-600 can cope with an ethernet saturated with its packets :-)
- *
- * Since there are only 2 receive buffers in the DE-600
- * and it takes some time to copy from the adapter,
- * this is absolutely necessary for any TCP performance whatsoever!
- *
- */
-#define min(a,b) ((a)<(b)?(a):(b))
-static unsigned long
-d_link_rspace(struct sock *sk)
-{
- int amt;
-
- if (sk != NULL) {
-/*
- * Hack! You might want to play with commenting away the following line,
- * if you know what you do!
- */
- sk->max_unacked = D_LINK_MAX_WINDOW - D_LINK_TCP_WINDOW_DIFF;
-
- if (sk->rmem_alloc >= SK_RMEM_MAX-2*D_LINK_MIN_WINDOW) return(0);
- amt = min((SK_RMEM_MAX-sk->rmem_alloc)/2-D_LINK_MIN_WINDOW, D_LINK_MAX_WINDOW);
- if (amt < 0) return(0);
- return(amt);
- }
- return(0);
-}
-
-
-#endif
+++ /dev/null
-/*
- * These are the functions used to load COFF IBSC style executables.
- * Information on COFF format may be obtained in either the Intel Binary
- * Compatibility Specification 2 or O'Rilley's book on COFF. The shared
- * libraries are defined only the in the Intel book.
- *
- * This file is based upon code written by Eric Youndale for the ELF object
- * file format.
- *
- * Author: Al Longyear (longyear@sii.com)
- *
- * Latest Revision:
- * 3 Feburary 1994
- * Al Longyear (longyear@sii.com)
- * Cleared first page of bss section using put_fs_byte.
- */
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <asm/segment.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/coff.h>
-#include <linux/malloc.h>
-
-asmlinkage int sys_exit (int exit_code);
-asmlinkage int sys_close (unsigned fd);
-asmlinkage int sys_open (const char *, int, int);
-asmlinkage int sys_uselib(const char * library);
-
-static int preload_library (struct linux_binprm *exe_bprm,
- COFF_SCNHDR * sect,
- struct file *fp);
-
-static int load_object (struct linux_binprm *bprm,
- struct pt_regs *regs,
- int lib_ok);
-
-/*
- * Small procedure to test for the proper file alignment.
- */
-
-static inline int
-is_properly_aligned (COFF_SCNHDR *sect)
-{
- long scnptr = COFF_LONG (sect->s_scnptr);
- long vaddr = COFF_LONG (sect->s_vaddr);
-/*
- * Print the section information if needed
- */
-
-#ifdef COFF_DEBUG
- printk ("%s, scnptr = %d, vaddr = %d\n",
- sect->s_name,
- scnptr, vaddr);
-#endif
-
-/*
- * Return the error code if the section is not properly aligned.
- */
-
-#ifdef COFF_DEBUG
- if (((vaddr - scnptr) & ~PAGE_MASK) != 0)
- printk ("bad alignment in %s\n", sect->s_name);
-#endif
- return ((((vaddr - scnptr) & ~PAGE_MASK) != 0) ? -ENOEXEC : 0);
-}
-
-/*
- * Clear the bytes in the last page of data.
- */
-
-static
-int clear_memory (unsigned long addr, unsigned long size)
-{
- int status;
-
- size = (PAGE_SIZE - (addr & ~PAGE_MASK)) & ~PAGE_MASK;
- if (size == 0)
- status = 0;
- else {
-
-#ifdef COFF_DEBUG
- printk ("un-initialized storage in last page %d\n", size);
-#endif
-
- status = verify_area (VERIFY_WRITE,
- (void *) addr, size);
-#ifdef COFF_DEBUG
- printk ("result from verify_area = %d\n", status);
-#endif
-
- if (status >= 0)
- while (size-- != 0)
- put_fs_byte (0, addr++);
- }
- return status;
-}
-
-/*
- * Helper function to process the load operation.
- */
-
-static int
-load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok)
-{
- COFF_FILHDR *coff_hdr = (COFF_FILHDR *) bprm->buf; /* COFF Header */
- COFF_SCNHDR *sect_bufr; /* Pointer to section table */
- COFF_SCNHDR *text_sect; /* Pointer to the text section */
- COFF_SCNHDR *data_sect; /* Pointer to the data section */
- COFF_SCNHDR *bss_sect; /* Pointer to the bss section */
- int text_count; /* Number of text sections */
- int data_count; /* Number of data sections */
- int bss_count; /* Number of bss sections */
- int lib_count; /* Number of lib sections */
- unsigned int start_addr = 0;/* Starting location for program */
- int status = 0; /* Result status register */
- int fd = -1; /* Open file descriptor */
- struct file *fp = NULL; /* Pointer to the file at "fd" */
- short int sections = 0; /* Number of sections in the file */
- short int aout_size = 0; /* Size of the a.out header area */
- short int flags; /* Flag bits from the COFF header */
-
-#ifdef COFF_DEBUG
- printk ("binfmt_coff entry: %s\n", bprm->filename);
-#endif
-
-/*
- * Validate the magic value for the object file.
- */
- do {
- if (COFF_I386BADMAG (*coff_hdr)) {
-#ifdef COFF_DEBUG
- printk ("bad filehdr magic\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * The object file should have 32 BIT little endian format. Do not allow
- * it to have the 16 bit object file flag set as Linux is not able to run
- * on the 80286/80186/8086.
- */
- flags = COFF_SHORT (coff_hdr->f_flags);
- if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) {
-#ifdef COFF_DEBUG
- printk ("invalid f_flags bits\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * Extract the header information which we need.
- */
- sections = COFF_SHORT (coff_hdr->f_nscns); /* Number of sections */
- aout_size = COFF_SHORT (coff_hdr->f_opthdr); /* Size of opt. headr */
-/*
- * If the file is not executable then reject the exectution. This means
- * that there must not be external references.
- */
- if ((flags & COFF_F_EXEC) == 0) {
-#ifdef COFF_DEBUG
- printk ("not executable bit\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * There must be atleast one section.
- */
- if (sections == 0) {
-#ifdef COFF_DEBUG
- printk ("no sections\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * Do some additional consistency checks.
- * The system requires mapping for this loader. If you try
- * to use a file system with no mapping, the format is not valid.
- */
- if (!bprm->inode->i_op ||
- !bprm->inode->i_op->default_file_ops->mmap) {
-#ifdef COFF_DEBUG
- printk ("no mmap in fs\n");
-#endif
- status = -ENOEXEC;
- }
- }
- while (0);
-/*
- * Allocate a buffer to hold the entire coff section list.
- */
- if (status >= 0) {
- int nbytes = sections * COFF_SCNHSZ;
-
- sect_bufr = (COFF_SCNHDR *) kmalloc (nbytes, GFP_KERNEL);
- if (0 == sect_bufr) {
-#ifdef COFF_DEBUG
- printk ("kmalloc failed\n");
-#endif
- status = -ENOEXEC;
- }
-/*
- * Read the section list from the disk file.
- */
- else {
- int old_fs = get_fs ();
- set_fs (get_ds ()); /* Make it point to the proper location */
- status = read_exec (bprm->inode, /* INODE for file */
- aout_size + COFF_FILHSZ, /* Offset in the file */
- (char *) sect_bufr, /* Buffer for read */
- nbytes); /* Byte count reqd. */
- set_fs (old_fs); /* Restore the selector */
-#ifdef COFF_DEBUG
- if (status < 0)
- printk ("read aout hdr, status = %d\n", status);
-#endif
- }
- }
- else
- sect_bufr = NULL; /* Errors do not have a section buffer */
-/*
- * Count the number of sections for the required types and store the location
- * of the last section for the three primary types.
- */
- text_count = 0;
- data_count = 0;
- bss_count = 0;
- lib_count = 0;
-
- text_sect = NULL;
- data_sect = NULL;
- bss_sect = NULL;
-/*
- * Loop through the sections and find the various types
- */
- if (status >= 0) {
- int nIndex;
- COFF_SCNHDR *sect_ptr = sect_bufr;
-
- for (nIndex = 0; nIndex < sections; ++nIndex) {
- long int sect_flags = COFF_LONG (sect_ptr->s_flags);
-
- switch (sect_flags) {
- case COFF_STYP_TEXT:
- text_sect = sect_ptr;
- ++text_count;
- status = is_properly_aligned (sect_ptr);
- break;
-
- case COFF_STYP_DATA:
- data_sect = sect_ptr;
- ++data_count;
- status = is_properly_aligned (sect_ptr);
- break;
-
- case COFF_STYP_BSS:
- bss_sect = sect_ptr;
- ++bss_count;
- break;
-
- case COFF_STYP_LIB:
-#ifdef COFF_DEBUG
- printk (".lib section found\n");
-#endif
- ++lib_count;
- break;
-
- default:
- break;
- }
- sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ];
- }
-/*
- * Ensure that there are the required sections. There must be one text
- * sections and one each of the data and bss sections for an executable.
- * A library may or may not have a data / bss section.
- */
- if (text_count != 1) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("no text sections\n");
-#endif
- }
- else {
- if (lib_ok) {
- if (data_count != 1 || bss_count != 1) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("no .data nor .bss sections\n");
-#endif
- }
- }
- }
- }
-/*
- * If there is no additional header then assume the file starts at
- * the first byte of the text section. This may not be the proper place,
- * so the best solution is to include the optional header. A shared library
- * __MUST__ have an optional header to indicate that it is a shared library.
- */
- if (status >= 0) {
- if (aout_size == 0) {
- if (!lib_ok) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("no header in library\n");
-#endif
- }
- start_addr = COFF_LONG (text_sect->s_vaddr);
- }
-/*
- * There is some header. Ensure that it is sufficient.
- */
- else {
- if (aout_size < COFF_AOUTSZ) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("header too small\n");
-#endif
- }
- else {
- COFF_AOUTHDR *aout_hdr = /* Pointer to a.out header */
- (COFF_AOUTHDR *) & ((char *) coff_hdr)[COFF_FILHSZ];
- short int aout_magic = COFF_SHORT (aout_hdr->magic); /* id */
-/*
- * Validate the magic number in the a.out header. If it is valid then
- * update the starting symbol location. Do not accept these file formats
- * when loading a shared library.
- */
- switch (aout_magic) {
- case COFF_OMAGIC:
- case COFF_ZMAGIC:
- case COFF_STMAGIC:
- if (!lib_ok) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("wrong a.out header magic\n");
-#endif
- }
- start_addr = (unsigned int) COFF_LONG (aout_hdr->entry);
- break;
-/*
- * Magic value for a shared library. This is valid only when loading a
- * shared library. (There is no need for a start_addr. It won't be used.)
- */
- case COFF_SHMAGIC:
- if (lib_ok) {
-#ifdef COFF_DEBUG
- printk ("wrong a.out header magic\n");
-#endif
- status = -ENOEXEC;
- }
- break;
-
- default:
-#ifdef COFF_DEBUG
- printk ("wrong a.out header magic\n");
-#endif
- status = -ENOEXEC;
- break;
- }
- }
- }
- }
-/*
- * Fetch a file pointer to the executable.
- */
- if (status >= 0) {
- fd = open_inode (bprm->inode, O_RDONLY);
- if (fd < 0) {
-#ifdef COFF_DEBUG
- printk ("can not open inode, result = %d\n", fd);
-#endif
- status = fd;
- }
- else
- fp = current->files->fd[fd];
- }
- else
- fd = -1; /* Invalidate the open file descriptor */
-/*
- * Generate the proper values for the text fields
- *
- * THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD
- * SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD.
- */
- if (status >= 0) {
- long text_scnptr = COFF_LONG (text_sect->s_scnptr);
- long text_size = COFF_LONG (text_sect->s_size);
- long text_vaddr = COFF_LONG (text_sect->s_vaddr);
-
- long data_scnptr;
- long data_size;
- long data_vaddr;
-
- long bss_size;
- long bss_vaddr;
-/*
- * Generate the proper values for the data fields
- */
- if (data_sect != NULL) {
- data_scnptr = COFF_LONG (data_sect->s_scnptr);
- data_size = COFF_LONG (data_sect->s_size);
- data_vaddr = COFF_LONG (data_sect->s_vaddr);
- }
- else {
- data_scnptr = 0;
- data_size = 0;
- data_vaddr = 0;
- }
-/*
- * Generate the proper values for the bss fields
- */
- if (bss_sect != NULL) {
- bss_size = COFF_LONG (bss_sect->s_size);
- bss_vaddr = COFF_LONG (bss_sect->s_vaddr);
- }
- else {
- bss_size = 0;
- bss_vaddr = 0;
- }
-/*
- * Flush the executable from memory. At this point the executable is
- * committed to being defined or a segmentation violation will occur.
- */
- if (lib_ok) {
-#ifdef COFF_DEBUG
- printk ("flushing executable\n");
-#endif
- flush_old_exec (bprm);
-/*
- * Define the initial locations for the various items in the new process
- */
- current->mm->mmap = NULL;
- current->mm->rss = 0;
-/*
- * Construct the parameter and environment string table entries.
- */
- bprm->p += change_ldt (0, bprm->page);
- bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
- bprm->p = (unsigned long) create_tables ((char *) bprm->p,
- bprm->argc,
- bprm->envc,
- 1);
-/*
- * Do the end processing once the stack has been constructed
- */
- current->mm->start_code = text_vaddr & PAGE_MASK;
- current->mm->end_code = text_vaddr + text_size;
- current->mm->end_data = data_vaddr + data_size;
- current->mm->start_brk =
- current->mm->brk = bss_vaddr + bss_size;
- current->suid =
- current->euid = bprm->e_uid;
- current->sgid =
- current->egid = bprm->e_gid;
- current->executable = bprm->inode; /* Store inode for file */
- ++bprm->inode->i_count; /* Count the open inode */
- regs->eip = start_addr; /* Current EIP register */
- regs->esp =
- current->mm->start_stack = bprm->p;
- }
-/*
- * Map the text pages
- */
-
-#ifdef COFF_DEBUG
- printk (".text: vaddr = %d, size = %d, scnptr = %d\n",
- text_vaddr,
- text_size,
- text_scnptr);
-#endif
- status = do_mmap (fp,
- text_vaddr & PAGE_MASK,
- text_size + (text_vaddr & ~PAGE_MASK),
- PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_SHARED,
- text_scnptr & PAGE_MASK);
-
- status = (status == (text_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
-/*
- * Map the data pages
- */
- if (status >= 0 && data_size != 0) {
-#ifdef COFF_DEBUG
- printk (".data: vaddr = %d, size = %d, scnptr = %d\n",
- data_vaddr,
- data_size,
- data_scnptr);
-#endif
- status = do_mmap (fp,
- data_vaddr & PAGE_MASK,
- data_size + (data_vaddr & ~PAGE_MASK),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE,
- data_scnptr & PAGE_MASK);
-
- status = (status == (data_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
- }
-/*
- * Construct the bss data for the process. The bss ranges from the
- * end of the data (which may not be on a page boundry) to the end
- * of the bss section. Allocate any necessary pages for the data.
- */
- if (status >= 0 && bss_size != 0) {
-#ifdef COFF_DEBUG
- printk (".bss: vaddr = %d, size = %d\n",
- bss_vaddr,
- bss_size);
-#endif
- zeromap_page_range (PAGE_ALIGN (bss_vaddr),
- PAGE_ALIGN (bss_size),
- PAGE_COPY);
-
- status = clear_memory (bss_vaddr, bss_size);
- }
-/*
- * Load any shared library for the executable.
- */
- if (status >= 0 && lib_ok && lib_count != 0) {
- int nIndex;
- COFF_SCNHDR *sect_ptr = sect_bufr;
-/*
- * Find the library sections. (There should be atleast one. It was counted
- * earlier.) This will evenutally recurse to our code and load the shared
- * library with our own procedures.
- */
- for (nIndex = 0; nIndex < sections; ++nIndex) {
- long int sect_flags = COFF_LONG (sect_ptr->s_flags);
- if (sect_flags == COFF_STYP_LIB) {
- status = preload_library (bprm, sect_ptr, fp);
- if (status != 0)
- break;
- }
- sect_ptr = (COFF_SCNHDR *) &((char *) sect_ptr) [COFF_SCNHSZ];
- }
- }
-/*
- * Generate any needed trap for this process. If an error occured then
- * generate a segmentation violation. If the process is being debugged
- * then generate the load trap. (Note: If this is a library load then
- * do not generate the trap here. Pass the error to the caller who
- * will do it for the process in the outer lay of this procedure call.)
- */
- if (lib_ok) {
- if (status < 0)
- send_sig (SIGSEGV, current, 0); /* Generate the error trap */
- else {
- if (current->flags & PF_PTRACED)
- send_sig (SIGTRAP, current, 0);
- }
- status = 0; /* We are committed. It can't fail */
- }
- }
-/*
- * Do any cleanup processing
- */
- if (fd >= 0)
- sys_close (fd); /* Close unused code file */
-
- if (sect_bufr != NULL)
- kfree (sect_bufr); /* Release section list buffer */
-/*
- * Return the completion status.
- */
-#ifdef COFF_DEBUG
- printk ("binfmt_coff: result = %d\n", status);
-#endif
- return (status);
-}
-
-/*
- * This procedure will load the library listed in the file name given
- * as the paramter. The result will be non-zero should something fail
- * to load.
- */
-
-static int
-preload_this_library (struct linux_binprm *exe_bprm, char *lib_name)
-{
- int status;
- int old_fs = get_fs();
-/*
- * If debugging then print "we have arrived"
- */
-#ifdef COFF_DEBUG
- printk ("%s loading shared library %s\n",
- exe_bprm->filename,
- lib_name);
-#endif
-/*
- * Change the FS register to the proper kernel address space and attempt
- * to load the library. The library name is allocated from the kernel
- * pool.
- */
- set_fs (get_ds ());
- status = sys_uselib (lib_name);
- set_fs (old_fs);
-/*
- * Return the success/failure to the caller.
- */
- return (status);
-}
-
-/*
- * This procedure is called to load a library section. The various
- * libraries are loaded from the list given in the section data.
- */
-
-static int
-preload_library (struct linux_binprm *exe_bprm,
- COFF_SCNHDR * sect, struct file *fp)
-{
- int status = 0; /* Completion status */
- long nbytes; /* Count of bytes in the header area */
-/*
- * Fetch the size of the section. There must be enough room for atleast
- * one entry.
- */
- nbytes = COFF_LONG (sect->s_size);
- if (nbytes < COFF_SLIBSZ) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("library section too small\n");
-#endif
- }
-/*
- * Allocate a buffer to hold the section data
- */
- else {
- COFF_SLIBHD *phdr;
- char *buffer = (char *) kmalloc (nbytes, GFP_KERNEL);
-
- if (0 == buffer) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("kmalloc failed\n");
-#endif
- }
- else {
- int old_fs = get_fs ();
-/*
- * Read the section data from the disk file.
- */
- set_fs (get_ds ()); /* Make it point to the proper location */
- status = read_exec (exe_bprm->inode, /* INODE for file */
- COFF_LONG (sect->s_scnptr), /* Disk location */
- buffer, /* Buffer for read */
- nbytes); /* Byte count reqd. */
- set_fs (old_fs); /* Restore the selector */
-/*
- * Check the result. The value returned is the byte count actaully read.
- */
- if (status >= 0 && status != nbytes) {
-#ifdef COFF_DEBUG
- printk ("read of lib section was short\n");
-#endif
- status = -ENOEXEC;
- }
- }
-/*
- * At this point, go through the list of libraries in the data area.
- */
- phdr = (COFF_SLIBHD *) buffer;
- while (status >= 0 && nbytes > COFF_SLIBSZ) {
- int entry_size = COFF_LONG (phdr->sl_entsz) * sizeof (long);
- int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
-/*
- * Validate the sizes of the various items. I don't trust the linker!!
- */
- if ((unsigned) header_size >= (unsigned) nbytes ||
- entry_size <= 0 ||
- (unsigned) entry_size <= (unsigned) header_size) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("header count is invalid\n");
-#endif
- }
-/*
- * Load the library. Stop the load process on the first error.
- */
- else {
- status = preload_this_library (exe_bprm,
- &((char *) phdr)[header_size]);
-#ifdef COFF_DEBUG
- printk ("preload_this_library result = %d\n", status);
-#endif
- }
-/*
- * Point to the next library in the section data.
- */
- nbytes -= entry_size;
- phdr = (COFF_SLIBHD *) &((char *) phdr)[entry_size];
- }
-/*
- * Release the space for the library list.
- */
- if (buffer != NULL)
- kfree (buffer);
- }
-/*
- * Return the resulting status to the caller.
- */
- return (status);
-}
-
-/*
- * This procedure is called by the main load sequence. It will load
- * the executable and prepare it for execution. It provides the additional
- * parameters used by the recursive coff loader and tells the loader that
- * this is the main executable. How simple it is . . . .
- */
-
-int
-load_coff_binary (struct linux_binprm *bprm, struct pt_regs *regs)
-{
- return (load_object (bprm, regs, 1));
-}
-
-/*
- * Load the image for any shared library.
- *
- * This is called when we need to load a library based upon a file name.
- */
-
-int
-load_coff_library (int fd)
-{
- struct linux_binprm *bprm; /* Parameters for the load operation */
- int status; /* Status of the request */
-/*
- * Read the first portion of the file.
- */
- bprm = (struct linux_binprm *) kmalloc (sizeof (struct linux_binprm),
- GFP_KERNEL);
- if (0 == bprm) {
-#ifdef COFF_DEBUG
- printk ("kmalloc failed\n");
-#endif
- status = -ENOEXEC;
- }
- else {
- struct file *file; /* Pointer to the file table */
- struct pt_regs regs; /* Register work area */
- int old_fs = get_fs (); /* Previous FS register value */
-
- memset (bprm, '\0', sizeof (struct linux_binprm));
-
- file = current->files->fd[fd];
- bprm->inode = file->f_inode; /* The only item _really_ needed */
- bprm->filename = ""; /* Make it a legal string */
-/*
- * Read the section list from the disk file.
- */
- set_fs (get_ds ()); /* Make it point to the proper location */
- status = read_exec (bprm->inode, /* INODE for file */
- 0L, /* Offset in the file */
- bprm->buf, /* Buffer for read */
- sizeof (bprm->buf)); /* Size of the buffer */
- set_fs (old_fs); /* Restore the selector */
-/*
- * Try to load the library.
- */
- status = load_object (bprm, ®s, 0);
-/*
- * Release the work buffer and return the result.
- */
- kfree (bprm); /* Release the buffer area */
- }
-/*
- * Return the result of the load operation
- */
- return (status);
-}
+++ /dev/null
-/*
- * linux/fs/binfmt_elf.c
- */
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/shm.h>
-
-#include <asm/segment.h>
-
-asmlinkage int sys_exit(int exit_code);
-asmlinkage int sys_close(unsigned fd);
-asmlinkage int sys_open(const char *, int, int);
-asmlinkage int sys_brk(unsigned long);
-
-#define DLINFO_ITEMS 8
-
-#include <linux/elf.h>
-
-/* We need to explicitly zero any fractional pages
- after the data section (i.e. bss). This would
- contain the junk from the file that should not
- be in memory */
-
-static void padzero(int elf_bss){
- unsigned int fpnt, nbyte;
-
- if(elf_bss & 0xfff) {
-
- nbyte = (PAGE_SIZE - (elf_bss & 0xfff)) & 0xfff;
- if(nbyte){
- verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
-
- fpnt = elf_bss;
- while(fpnt & 0xfff) put_fs_byte(0, fpnt++);
- };
- };
-}
-
-unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs)
-{
- unsigned long *argv,*envp, *dlinfo;
- unsigned long * sp;
- struct vm_area_struct *mpnt;
-
- mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
- if (mpnt) {
- mpnt->vm_task = current;
- mpnt->vm_start = PAGE_MASK & (unsigned long) p;
- mpnt->vm_end = TASK_SIZE;
- mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
- mpnt->vm_share = NULL;
- mpnt->vm_inode = NULL;
- mpnt->vm_offset = 0;
- mpnt->vm_ops = NULL;
- insert_vm_struct(current, mpnt);
- current->mm->stk_vma = mpnt;
- }
- sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
- if(exec) sp -= DLINFO_ITEMS*2;
- dlinfo = sp;
- sp -= envc+1;
- envp = sp;
- sp -= argc+1;
- argv = sp;
- if (!ibcs) {
- put_fs_long((unsigned long)envp,--sp);
- put_fs_long((unsigned long)argv,--sp);
- }
-
- /* The constant numbers (0-9) that we are writing here are
- described in the header file sys/auxv.h on at least
- some versions of SVr4 */
- if(exec) { /* Put this here for an ELF program interpreter */
- struct elf_phdr * eppnt;
- eppnt = (struct elf_phdr *) exec->e_phoff;
- put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++);
- put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
- put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
- put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
- put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++);
- put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
- put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
- put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
- };
-
- put_fs_long((unsigned long)argc,--sp);
- current->mm->arg_start = (unsigned long) p;
- while (argc-->0) {
- put_fs_long((unsigned long) p,argv++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,argv);
- current->mm->arg_end = current->mm->env_start = (unsigned long) p;
- while (envc-->0) {
- put_fs_long((unsigned long) p,envp++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,envp);
- current->mm->env_end = (unsigned long) p;
- return sp;
-}
-
-
-/* This is much more generalized than the library routine read function,
- so we keep this separate. Techincally the library read function
- is only provided so that we can read a.out libraries that have
- an ELF header */
-
-static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
- struct inode * interpreter_inode)
-{
- struct file * file;
- struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- unsigned int len;
- unsigned int load_addr;
- int elf_exec_fileno;
- int elf_bss;
- int old_fs, retval;
- unsigned int last_bss;
- int error;
- int i, k;
-
- elf_bss = 0;
- last_bss = 0;
- error = load_addr = 0;
-
- /* First of all, some simple consistency checks */
- if((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) ||
- (!interpreter_inode->i_op || !interpreter_inode->i_op->bmap ||
- !interpreter_inode->i_op->default_file_ops->mmap)){
- return 0xffffffff;
- };
-
- /* Now read in all of the header information */
-
- if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
- return 0xffffffff;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL);
- if(!elf_phdata) return 0xffffffff;
-
- old_fs = get_fs();
- set_fs(get_ds());
- retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- set_fs(old_fs);
-
- elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
- if (elf_exec_fileno < 0) return 0xffffffff;
- file = current->files->fd[elf_exec_fileno];
-
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
- if(eppnt->p_type == PT_LOAD) {
- error = do_mmap(file,
- eppnt->p_vaddr & 0xfffff000,
- eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0),
- eppnt->p_offset & 0xfffff000);
-
- if(!load_addr && interp_elf_ex->e_type == ET_DYN)
- load_addr = error;
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if(k > elf_bss) elf_bss = k;
- if(error < 0 && error > -1024) break; /* Real error */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if(k > last_bss) last_bss = k;
- }
-
- /* Now use mmap to map the library into memory. */
-
-
- sys_close(elf_exec_fileno);
- if(error < 0 && error > -1024) {
- kfree(elf_phdata);
- return 0xffffffff;
- }
-
- padzero(elf_bss);
- len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */
-
- /* Map the last of the bss segment */
- if (last_bss > len)
- do_mmap(NULL, len, last_bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
-
- return ((unsigned int) interp_elf_ex->e_entry) + load_addr;
-}
-
-static unsigned int load_aout_interp(struct exec * interp_ex,
- struct inode * interpreter_inode)
-{
- int retval;
- unsigned int elf_entry;
-
- current->mm->brk = interp_ex->a_bss +
- (current->mm->end_data = interp_ex->a_data +
- (current->mm->end_code = interp_ex->a_text));
- elf_entry = interp_ex->a_entry;
-
-
- if (N_MAGIC(*interp_ex) == OMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode, 32, (char *) 0,
- interp_ex->a_text+interp_ex->a_data);
- } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode,
- N_TXTOFF(*interp_ex) ,
- (char *) N_TXTADDR(*interp_ex),
- interp_ex->a_text+interp_ex->a_data);
- } else
- retval = -1;
-
- if(retval >= 0)
- do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) &
- 0xfffff000, interp_ex->a_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- if(retval < 0) return 0xffffffff;
- return elf_entry;
-}
-
-/*
- * These are the functions used to load ELF style executables and shared
- * libraries. There is no binary dependent code anywhere else.
- */
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
- struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- struct file * file;
- struct exec interp_ex;
- struct inode *interpreter_inode;
- unsigned int load_addr;
- unsigned int interpreter_type = INTERPRETER_NONE;
- int i;
- int old_fs;
- int error;
- struct elf_phdr * elf_ppnt, *elf_phdata;
- int elf_exec_fileno;
- unsigned int elf_bss, k, elf_brk;
- int retval;
- char * elf_interpreter;
- unsigned int elf_entry;
- int status;
- unsigned int start_code, end_code, end_data;
- unsigned int elf_stack;
- char passed_fileno[6];
-
- status = 0;
- load_addr = 0;
- elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
- return -ENOEXEC;
-
-
- /* First of all, some simple consistency checks */
- if(elf_ex.e_type != ET_EXEC ||
- (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
- (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
- !bprm->inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- };
-
- /* Now read in all of the header information */
-
- elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
- elf_ex.e_phnum, GFP_KERNEL);
-
- old_fs = get_fs();
- set_fs(get_ds());
- retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
- set_fs(old_fs);
- if (retval < 0) {
- kfree (elf_phdata);
- return retval;
- }
-
- elf_ppnt = elf_phdata;
-
- elf_bss = 0;
- elf_brk = 0;
-
- elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
-
- if (elf_exec_fileno < 0) {
- kfree (elf_phdata);
- return elf_exec_fileno;
- }
-
- file = current->files->fd[elf_exec_fileno];
-
- elf_stack = 0xffffffff;
- elf_interpreter = NULL;
- start_code = 0;
- end_code = 0;
- end_data = 0;
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- for(i=0;i < elf_ex.e_phnum; i++){
- if(elf_ppnt->p_type == PT_INTERP) {
- /* This is the program interpreter used for shared libraries -
- for now assume that this is an a.out format binary */
-
- elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
- GFP_KERNEL);
-
- retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
- elf_ppnt->p_filesz);
-#if 0
- printk("Using ELF interpreter %s\n", elf_interpreter);
-#endif
- if(retval >= 0)
- retval = namei(elf_interpreter, &interpreter_inode);
- if(retval >= 0)
- retval = read_exec(interpreter_inode,0,bprm->buf,128);
-
- if(retval >= 0){
- interp_ex = *((struct exec *) bprm->buf); /* exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- };
- if(retval < 0) {
- kfree (elf_phdata);
- kfree(elf_interpreter);
- return retval;
- };
- };
- elf_ppnt++;
- };
-
- set_fs(old_fs);
-
- /* Some simple consistency checks for the interpreter */
- if(elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
- if(retval < 0) {
- kfree(elf_interpreter);
- kfree(elf_phdata);
- return -ELIBACC;
- };
- /* Now figure out which format our binary is */
- if((N_MAGIC(interp_ex) != OMAGIC) &&
- (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC))
- interpreter_type = INTERPRETER_ELF;
-
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
- interpreter_type &= ~INTERPRETER_ELF;
-
- if(!interpreter_type)
- {
- kfree(elf_interpreter);
- kfree(elf_phdata);
- return -ELIBBAD;
- };
- }
-
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
-
- if (!bprm->sh_bang) {
- char * passed_p;
-
- if(interpreter_type == INTERPRETER_AOUT) {
- sprintf(passed_fileno, "%d", elf_exec_fileno);
- passed_p = passed_fileno;
-
- if(elf_interpreter) {
- bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
- bprm->argc++;
- };
- };
- if (!bprm->p) {
- if(elf_interpreter) {
- kfree(elf_interpreter);
- }
- kfree (elf_phdata);
- return -E2BIG;
- }
- }
-
- /* OK, This is the point of no return */
- flush_old_exec(bprm);
-
- current->mm->end_data = 0;
- current->mm->end_code = 0;
- current->mm->start_mmap = ELF_START_MMAP;
- current->mm->mmap = NULL;
- elf_entry = (unsigned int) elf_ex.e_entry;
-
- /* Do this so that we can load the interpreter, if need be. We will
- change some of these later */
- current->mm->rss = 0;
- bprm->p += change_ldt(0, bprm->page);
- current->mm->start_stack = bprm->p;
-
- /* Now we do a little grungy work by mmaping the ELF image into
- the correct location in memory. At this point, we assume that
- the image should be loaded at fixed address, not at a variable
- address. */
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- elf_ppnt = elf_phdata;
- for(i=0;i < elf_ex.e_phnum; i++){
-
- if(elf_ppnt->p_type == PT_INTERP) {
- /* Set these up so that we are able to load the interpreter */
- /* Now load the interpreter into user address space */
- set_fs(old_fs);
-
- if(interpreter_type & 1) elf_entry =
- load_aout_interp(&interp_ex, interpreter_inode);
-
- if(interpreter_type & 2) elf_entry =
- load_elf_interp(&interp_elf_ex, interpreter_inode);
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- iput(interpreter_inode);
- kfree(elf_interpreter);
-
- if(elf_entry == 0xffffffff) {
- printk("Unable to load interpreter\n");
- kfree(elf_phdata);
- send_sig(SIGSEGV, current, 0);
- return 0;
- };
- };
-
-
- if(elf_ppnt->p_type == PT_LOAD) {
- error = do_mmap(file,
- elf_ppnt->p_vaddr & 0xfffff000,
- elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE,
- elf_ppnt->p_offset & 0xfffff000);
-
-#ifdef LOW_ELF_STACK
- if(elf_ppnt->p_vaddr & 0xfffff000 < elf_stack)
- elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
-#endif
-
- if(!load_addr)
- load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
- k = elf_ppnt->p_vaddr;
- if(k > start_code) start_code = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
- if(k > elf_bss) elf_bss = k;
- if((elf_ppnt->p_flags | PROT_WRITE) && end_code < k)
- end_code = k;
- if(end_data < k) end_data = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
- if(k > elf_brk) elf_brk = k;
- };
- elf_ppnt++;
- };
- set_fs(old_fs);
-
- kfree(elf_phdata);
-
- if(!elf_interpreter) sys_close(elf_exec_fileno);
- current->elf_executable = 1;
- current->executable = bprm->inode;
- bprm->inode->i_count++;
-#ifdef LOW_ELF_STACK
- current->start_stack = p = elf_stack - 4;
-#endif
- bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
- bprm->p = (unsigned long)
- create_elf_tables((char *)bprm->p,
- bprm->argc,
- bprm->envc,
- (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
- load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
- if(interpreter_type == INTERPRETER_AOUT)
- current->mm->arg_start += strlen(passed_fileno) + 1;
- current->mm->start_brk = current->mm->brk = elf_brk;
- current->mm->end_code = end_code;
- current->mm->start_code = start_code;
- current->mm->end_data = end_data;
- current->mm->start_stack = bprm->p;
- current->suid = current->euid = bprm->e_uid;
- current->sgid = current->egid = bprm->e_gid;
-
- /* Calling sys_brk effectively mmaps the pages that we need for the bss and break
- sections */
- current->mm->brk = (elf_bss + 0xfff) & 0xfffff000;
- sys_brk((elf_brk + 0xfff) & 0xfffff000);
-
- padzero(elf_bss);
-
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, 0);
-
- regs->eip = elf_entry; /* eip, magic happens :-) */
- regs->esp = bprm->p; /* stack pointer */
- if (current->flags & PF_PTRACED)
- send_sig(SIGTRAP, current, 0);
- return 0;
-}
-
-/* This is really simpleminded and specialized - we are loading an
- a.out library that is given an ELF header. */
-
-int load_elf_library(int fd){
- struct file * file;
- struct elfhdr elf_ex;
- struct elf_phdr *elf_phdata = NULL;
- struct inode * inode;
- unsigned int len;
- int elf_bss;
- int old_fs, retval;
- unsigned int bss;
- int error;
- int i,j, k;
-
- len = 0;
- file = current->files->fd[fd];
- inode = file->f_inode;
- elf_bss = 0;
-
- set_fs(KERNEL_DS);
- if (file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)) != sizeof(elf_ex)) {
- sys_close(fd);
- return -EACCES;
- }
- set_fs(USER_DS);
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
- return -ENOEXEC;
-
- /* First of all, some simple consistency checks */
- if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
- (!inode->i_op || !inode->i_op->bmap ||
- !inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- };
-
- /* Now read in all of the header information */
-
- if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
- return -ENOEXEC;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
-
- old_fs = get_fs();
- set_fs(get_ds());
- retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * elf_ex.e_phnum);
- set_fs(old_fs);
-
- j = 0;
- for(i=0; i<elf_ex.e_phnum; i++)
- if((elf_phdata + i)->p_type == PT_LOAD) j++;
-
- if(j != 1) {
- kfree(elf_phdata);
- return -ENOEXEC;
- };
-
- while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-
- /* Now use mmap to map the library into memory. */
- error = do_mmap(file,
- elf_phdata->p_vaddr & 0xfffff000,
- elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE,
- elf_phdata->p_offset & 0xfffff000);
-
- k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
- if(k > elf_bss) elf_bss = k;
-
- sys_close(fd);
- if (error != elf_phdata->p_vaddr & 0xfffff000) {
- kfree(elf_phdata);
- return error;
- }
-
- padzero(elf_bss);
-
- len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
- bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
- if (bss > len)
- do_mmap(NULL, len, bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
- return 0;
-}
dump_start = dump.u_tsize << 12;
dump_size = dump.u_dsize << 12;
DUMP_WRITE(dump_start,dump_size);
- };
+ }
/* Now prepare to dump the stack area */
if (dump.u_ssize != 0) {
dump_start = dump.start_stack;
dump_size = dump.u_ssize << 12;
DUMP_WRITE(dump_start,dump_size);
- };
+ }
/* Finally dump the task struct. Not be used by gdb, but could be useful */
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
if (error != N_TXTADDR(ex)) {
sys_close(fd);
send_sig(SIGSEGV, current, 0);
- return 0;
- };
+ return -EINVAL;
+ }
}
error = do_mmap(file, N_TXTADDR(ex) + ex.a_text, ex.a_data,
sys_close(fd);
if (error != N_TXTADDR(ex) + ex.a_text) {
send_sig(SIGSEGV, current, 0);
- return 0;
- };
+ return -EINVAL;
+ }
current->executable = bprm->inode;
bprm->inode->i_count++;
}
"EXECOMBINAPPSYSDRVOVLOVROBJLIBDLLPIF" /* program code */
"ARCZIPLHALZHZOOTARZ ARJ" /* common archivers */
"TZ TAZTZPTPZ" /* abbreviations of tar.Z and tar.zip */
+ "GZ TGZDEB" /* .gz, .tar.gz and Debian packages */
"GIFBMPTIFGL JPGPCX" /* graphics */
"TFMVF GF PK PXLDVI"; /* TeX */
extern int get_module_list(char *);
extern int get_device_list(char *);
extern int get_filesystem_list(char *);
+extern int get_ksyms_list(char *);
static int array_read(struct inode * inode, struct file * file,char * buf, int count)
{
case 19:
length = get_filesystem_list(page);
break;
+ case 20:
+ length = get_ksyms_list(page);
+ break;
default:
free_page((unsigned long) page);
return -EBADF;
{17,4,"stat" },
{18,7,"devices" },
{19,11,"filesystems" },
+ {20,5,"ksyms" },
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
/****************************************************************************************
* *
- * SCSI header library for linux *
+ * general (not only SCSI) header library for linux CDROM drivers *
* (C) 1992 David Giller rafetmad@oxy.edu *
+ * 1994 Eberhard Moenkeberg emoenke@gwdg.de ("read audio" and some other stuff) *
* *
* <linux/cdrom.h> -- CD-ROM IOCTLs and structs *
* *
#ifndef _LINUX_CDROM_H
#define _LINUX_CDROM_H
+/*
+ * some fix numbers
+ */
+#define CD_MINS 75 /* minutes per CD */
+#define CD_SECS 60 /* seconds per minute */
+#define CD_FRAMES 75 /* frames per second */
+#define CD_FRAMESIZE 2048 /* bytes per frame, cooked mode */
+#define CD_FRAMESIZE_XA 2340 /* bytes per frame, "xa" mode */
+#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */
+#define CD_FRAMESIZE_SUB 96 /* subchannel data size */
+#define CD_BLOCK_OFFSET 150 /* offset of first logical frame */
+#define CD_XA_HEAD 12 /* header size of XA frame */
+#define CD_XA_TAIL 280 /* tail size of XA frame */
+
/*
*
* For IOCTL calls, we will commandeer byte 0x53, or 'S'.
int cdread_buflen;
};
+/*
+ * preliminary extensions for transfering audio frames
+ * currently used by sbpcd.c
+ * (still may change if other drivers will use it, too):
+ */
+struct cdrom_read_audio
+ {
+ union
+ {
+ struct
+ {
+ u_char minute;
+ u_char second;
+ u_char frame;
+ } msf;
+ int lba;
+ } addr; /* frame address */
+ u_char addr_format; /* CDROM_LBA or CDROM_MSF */
+ int nframes; /* number of 2352-byte-frames to read at once, currently only 1 allowed */
+ u_char *buf; /* frame buffer (size: nframes*2352 bytes) */
+ };
+
#ifdef FIVETWELVE
#define CDROM_MODE1_SIZE 512
#else
#define CDROMPAUSE 0x5301 /* pause */
#define CDROMRESUME 0x5302 /* resume */
-#define CDROMPLAYMSF 0x5303 /* (stuct cdrom_msf) */
+#define CDROMPLAYMSF 0x5303 /* (struct cdrom_msf) */
/* SCMD_PLAY_AUDIO_MSF */
#define CDROMPLAYTRKIND 0x5304 /* (struct cdrom_ti) */
#define CDROMREADMODE1 0x530d /* (struct cdrom_read) */
/* read type-1 data */
+/*
+ * preliminary extension for transfering audio frames
+ * currently used by sbpcd.c
+ * (still may change if other drivers will use it, too):
+ */
+#define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */
#endif _LINUX_CDROM_H
+
+++ /dev/null
-#ifndef _LINUX_MKTIME_H
-#define _LINUX_MKTIME_H
-
-struct mktime {
- int sec;
- int min;
- int hour;
- int day;
- int mon;
- int year;
-};
-
-#endif
/*
* Dynamic loading of modules into the kernel.
+ *
+ * Modified by Bjorn Ekwall <bj0rn@blox.se>
*/
#ifndef _LINUX_MODULE_H
/* maximum length of symbol name */
#define SYM_MAX_NAME 60
+struct kernel_sym { /* sent to "insmod" */
+ unsigned long value; /* value of symbol */
+ char name[SYM_MAX_NAME]; /* name of symbol */
+};
+
+struct module_ref {
+ struct module *module;
+ struct module_ref *next;
+};
+
+struct internal_symbol {
+ void *addr;
+ char *name;
+ };
+
+struct symbol_table { /* received from "insmod" */
+ int size; /* total, including string table!!! */
+ int n_symbols;
+ int n_refs;
+ struct internal_symbol symbol[0]; /* actual size defined by n_symbols */
+ struct module_ref ref[0]; /* actual size defined by n_refs */
+};
+/*
+ * Note: The string table follows immediately after the symbol table in memory!
+ */
struct module {
struct module *next;
+ struct module_ref *ref; /* the list of modules that refer to me */
+ struct symbol_table *symtab;
char *name;
int size; /* size of module in pages */
void* addr; /* address of module */
void (*cleanup)(void); /* cleanup routine */
};
-
struct mod_routines {
int (*init)(void); /* initialization routine */
void (*cleanup)(void); /* cleanup routine */
};
-
-struct kernel_sym {
- unsigned long value; /* value of symbol */
- char name[SYM_MAX_NAME]; /* name of symbol */
-};
-
-extern struct module *module_list;
+/* rename_module_symbol(old_name, new_name) WOW! */
+extern int rename_module_symbol(char *, char *);
/*
* sbpcd=0x300,LaserMate
* or
* sbpcd=0x330,SPEA
- * these strings are case sensitive !!!
+ *
+ * and, if you have a second CDROM controller board,
+ * sbpcd2=0x310,LaserMate
+ * and so on.
+ *
+ * These strings are case sensitive !!!
*/
-/*
- * change this to select the type of your interface board:
+/*
+ * put your CDROM port base address into CDROM_PORT
+ * and specify the type of your interface in SBPRO.
+ *
+ * SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
+ * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ...
+ * SPEA addresses are 0x320, 0x330, 0x340, 0x350
+ * there are some soundcards on the market with 0x0630, 0x0650, ...
+ *
+ * example: if your SBPRO audio address is 0x220, specify 0x230.
+ *
*
* set SBPRO to 1 for "true" SoundBlaster card
* set SBPRO to 0 for "poor" (no sound) interface cards
* (currently I do not know any "compatible" with SBPRO 1)
* then I can include better information with the next release.
*/
+#if !(SBPCD_ISSUE-1) /* first (or if you have only one) interface board: */
+#define CDROM_PORT 0x0230
#define SBPRO 1
+#endif
+
+/* ignore the rest if you have only one interface board & driver */
+
+#if !(SBPCD_ISSUE-2) /* second interface board: */
+#define CDROM_PORT 0x0370
+#define SBPRO 0
+#endif
+#if !(SBPCD_ISSUE-3) /* third interface board: */
+#define CDROM_PORT 0x0330
+#define SBPRO 0
+#endif
+#if !(SBPCD_ISSUE-4) /* fourth interface board: */
+#define CDROM_PORT 0x0340
+#define SBPRO 0
+#endif
+/*==========================================================================*/
+/*==========================================================================*/
/*
- * put your CDROM port base address here:
- * SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
- * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ...
- * SPEA addresses are 0x320, 0x330, 0x340, 0x350
- * there are some soundcards on the market with 0x0630, 0x0650, ...
- *
- * example: if your SBPRO audio address is 0x220, specify 0x230.
- *
+ * nothing to change below here if you are not experimenting
*/
-#define CDROM_PORT 0x0230
+#ifndef _LINUX_SBPCD_H
+#define _LINUX_SBPCD_H
/*==========================================================================*/
/*==========================================================================*/
/*
- * nothing to change below here if you are not experimenting
+ * to fork and execute a function after some elapsed time:
+ * one "jifs" unit is 10 msec.
*/
+#undef MY_TIMER
+#undef SET_TIMER
+#undef CLEAR_TIMER
+
+#if !(SBPCD_ISSUE-1)
+#define MY_TIMER SBPCD_TIMER
+#endif
+#if !(SBPCD_ISSUE-2)
+#define MY_TIMER SBPCD2_TIMER
+#endif
+#if !(SBPCD_ISSUE-3)
+#define MY_TIMER SBPCD3_TIMER
+#endif
+#if !(SBPCD_ISSUE-4)
+#define MY_TIMER SBPCD4_TIMER
+#endif
+
+#define SET_TIMER(func, jifs) \
+ ((timer_table[MY_TIMER].expires = jiffies + jifs), \
+ (timer_table[MY_TIMER].fn = func), \
+ (timer_active |= 1<<MY_TIMER))
+
+#define CLEAR_TIMER timer_active &= ~(1<<MY_TIMER)
+
/*==========================================================================*/
/*==========================================================================*/
/*
#define DBG_LCK 23 /* door (un)lock info */
#define DBG_SQ 24 /* dump SubQ frame */
#define DBG_AUD 25 /* "read audio" debugging */
-#define DBG_000 26 /* unnecessary information */
+#define DBG_SEQ 26 /* Sequoia interface configuration trace */
+#define DBG_000 27 /* unnecessary information */
/*==========================================================================*/
/*==========================================================================*/
#define READ_SC 0x04 /* "subchannel info": 96 bytes per frame */
#define READ_AU 0x08 /* "audio frame": 2352 bytes per frame */
-/*
- * preliminary extensions to cdrom.h for transfering audio frames:
- */
-#define CDROMREADAUDIO 0xE0 /* IOCTL function (arg = &cdrom_aud) */
-
-struct cdrom_aud { u_int lba; /* frame address */
- u_char *buf; /* frame buffer (2352 bytes) */
- };
-
/*
* sense byte: used only if new_drive
* only during cmd 09 00 xx ah al 00 00
*
* values: 00
- * 82
+ * 82 "raw audio" mode
* xx from infobuf[0] after 85 00 00 00 00 00 00
*/
-
-#define CD_MINS 75 /* minutes per CD */
-#define CD_SECS 60 /* seconds per minutes */
-#define CD_FRAMES 75 /* frames per second */
-#define CD_FRAMESIZE 2048 /* bytes per frame, data mode */
-#define CD_FRAMESIZE_XA 2340 /* bytes per frame, "xa" mode */
-#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */
-#define CD_FRAMESIZE_SUB 96 /* subchannel data size */
-#define CD_BLOCK_OFFSET 150 /* offset of first logical frame */
-#define CD_XA_HEAD 12 /* header size of XA frame */
-#define CD_XA_TAIL 280 /* tail size of XA frame */
-
/* audio status (bin) */
#define aud_00 0x00 /* Audio status byte not supported or not valid */
#define audx11 0x0b /* Audio play operation in progress */
/*
* highest allowed drive number (MINOR+1)
- * currently only one controller, maybe later up to 4
*/
#define NR_SBPCD 4
*/
#define READ_DATA(port, buf, nr) insb(port, buf, nr)
-/*==========================================================================*/
-/*
- * to fork and execute a function after some elapsed time:
- * one "jifs" unit is 10 msec.
- */
-#define SET_TIMER(func, jifs) \
- ((timer_table[SBPCD_TIMER].expires = jiffies + jifs), \
- (timer_table[SBPCD_TIMER].fn = func), \
- (timer_active |= 1<<SBPCD_TIMER))
-
-#define CLEAR_TIMER timer_active &= ~(1<<SBPCD_TIMER)
-
/*==========================================================================*/
/*
* Creative Labs Programmers did this:
*/
#define MAX_TRACKS 120 /* why more than 99? */
-
/*==========================================================================*/
/*
* To make conversions easier (machine dependent!)
BLK;
/*==========================================================================*/
+#endif _LINUX_SBPCD_H
extern int vsprintf(char *,const char *,va_list);
extern void init(void);
extern void init_IRQ(void);
+extern void init_modules(void);
extern long kmalloc_init (long,long);
extern long blk_dev_init(long,long);
extern long chr_dev_init(long,long);
init_IRQ();
sched_init();
parse_options(command_line);
+ init_modules();
#ifdef CONFIG_PROFILE
prof_buffer = (unsigned long *) memory_start;
prof_len = (unsigned long) &end;
* Herein lies all the functions/variables that are "exported" for linkage
* with dynamically loaded kernel modules.
* Jon.
+ *
+ * Stacked module support and unified symbol table added by
+ * Bjorn Ekwall <bj0rn@blox.se>
*/
#include <linux/autoconf.h>
#include <linux/interrupt.h>
#include <linux/binfmts.h>
#include <linux/personality.h>
+#include <linux/module.h>
#ifdef CONFIG_INET
#include <linux/netdevice.h>
#endif
+
+#include <asm/irq.h>
extern void *sys_call_table;
+/* must match struct internal_symbol !!! */
#define X(name) { (void *) &name, "_" #name }
#ifdef CONFIG_FTAPE
extern int dev_rint(unsigned char *, long, int, struct device *);
extern void dev_tint(struct device *);
extern struct device *irq2dev_map[];
+extern void dev_kfree_skb(struct sk_buff *, int);
#endif
-struct {
- void *addr;
- const char *name;
-} symbol_table[] = {
+struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
+ {
+ /* stackable module support */
+ X(rename_module_symbol),
+
/* system info variables */
X(EISA_bus),
X(wp_works_ok),
X(irqaction),
X(request_irq),
X(free_irq),
+ X(enable_irq),
+ X(disable_irq),
X(bh_active),
X(bh_mask),
X(dev_rint),
X(dev_tint),
X(irq2dev_map),
+ X(dev_kfree_skb),
#endif
+
+ /********************************************************
+ * Do not add anything below this line,
+ * as the stacked modules depend on this!
+ */
+ { NULL, NULL } /* mark end of table */
+ },
+ { NULL, NULL } /* no module refs */
};
+/*
int symbol_table_size = sizeof (symbol_table) / sizeof (symbol_table[0]);
+*/
+++ /dev/null
-/*
- * linux/kernel/mktime.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-#include <linux/mktime.h>
-
-/*
- * This isn't the library routine, it is only used in the kernel.
- * as such, we don't care about years<1970 etc, but assume everything
- * is ok. Similarly, TZ etc is happily ignored. We just do everything
- * as easily as possible. Let's find something public for the library
- * routines (although I think minix times is public).
- */
-/*
- * PS. I hate whoever though up the year 1970 - couldn't they have gotten
- * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy.
- */
-#define MINUTE 60
-#define HOUR (60*MINUTE)
-#define DAY (24*HOUR)
-#define YEAR (365*DAY)
-
-/* interestingly, we assume leap-years */
-static int month[12] = {
- 0,
- DAY*(31),
- DAY*(31+29),
- DAY*(31+29+31),
- DAY*(31+29+31+30),
- DAY*(31+29+31+30+31),
- DAY*(31+29+31+30+31+30),
- DAY*(31+29+31+30+31+30+31),
- DAY*(31+29+31+30+31+30+31+31),
- DAY*(31+29+31+30+31+30+31+31+30),
- DAY*(31+29+31+30+31+30+31+31+30+31),
- DAY*(31+29+31+30+31+30+31+31+30+31+30)
-};
-
-long kernel_mktime(struct mktime * time)
-{
- long res;
- int year;
-
- year = time->year - 70;
-/* magic offsets (y+1) needed to get leapyears right.*/
- res = YEAR*year + DAY*((year+1)/4);
- res += month[time->mon];
-/* and (y+2) here. If it wasn't a leap-year, we have to adjust */
- if (time->mon>1 && ((year+2)%4))
- res -= DAY;
- res += DAY*(time->day-1);
- res += HOUR*time->hour;
- res += MINUTE*time->min;
- res += time->sec;
- return res;
-}
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/malloc.h>
+/*
+ * Heavily modified by Bjorn Ekwall <bj0rn@blox.se> May 1994 (C)
+ * This source is covered by the GNU GPL, the same as all kernel sources.
+ *
+ * Features:
+ * - Supports stacked modules (removeable only of there are no dependants).
+ * - Supports table of symbols defined by the modules.
+ * - Supports /proc/ksyms, showing value, name and owner of all
+ * the symbols defined by all modules (in stack order).
+ * - Added module dependencies information into /proc/modules
+ * - Supports redefines of all symbols, for streams-like behaviour.
+ * - Compatible with older versions of insmod.
+ *
+ */
+
+#ifdef DEBUG_MODULE
+#define PRINTK(a) printk a
+#else
+#define PRINTK(a) /* */
+#endif
+
+static struct module kernel_module;
+static struct module *module_list = &kernel_module;
+
+static int freeing_modules; /* true if some modules are marked for deletion */
+
+static struct module *find_module( const char *name);
+static int get_mod_name( char *user_name, char *buf);
+static int free_modules( void);
+
+
+/*
+ * Called at boot time
+ */
+void init_modules(void) {
+ extern struct symbol_table symbol_table; /* in kernel/ksyms.c */
+ struct internal_symbol *sym;
+ int i;
-struct module *module_list = NULL;
-int freeing_modules; /* true if some modules are marked for deletion */
+ for (i = 0, sym = symbol_table.symbol; sym->name; ++sym, ++i)
+ ;
+ symbol_table.n_symbols = i;
-struct module *find_module( const char *name);
-int get_mod_name( char *user_name, char *buf);
-int free_modules( void);
+ kernel_module.symtab = &symbol_table;
+ kernel_module.state = MOD_RUNNING; /* Hah! */
+ kernel_module.name = "";
+}
+
+int
+rename_module_symbol(char *old_name, char *new_name)
+{
+ struct internal_symbol *sym;
+ int i = 0; /* keep gcc silent */
+
+ if (module_list->symtab) {
+ sym = module_list->symtab->symbol;
+ for (i = module_list->symtab->n_symbols; i > 0; ++sym, --i) {
+ if (strcmp(sym->name, old_name) == 0) { /* found it! */
+ sym->name = new_name; /* done! */
+ PRINTK(("renamed %s to %s\n", old_name, new_name));
+ return 1; /* it worked! */
+ }
+ }
+ }
+ printk("rename %s to %s failed!\n", old_name, new_name);
+ return 0; /* not there... */
+
+ /*
+ * This one will change the name of the first matching symbol!
+ *
+ * With this function, you can replace the name of a symbol defined
+ * in the current module with a new name, e.g. when you want to insert
+ * your own function instead of a previously defined function
+ * with the same name.
+ *
+ * "Normal" usage:
+ *
+ * bogus_function(int params)
+ * {
+ * do something "smart";
+ * return real_function(params);
+ * }
+ *
+ * ...
+ *
+ * init_module()
+ * {
+ * if (rename_module_symbol("_bogus_function", "_real_function"))
+ * printk("yep!\n");
+ * else
+ * printk("no way!\n");
+ * ...
+ * }
+ *
+ * When loading this module, real_function will be resolved
+ * to the real function address.
+ * All later loaded modules that refer to "real_function()" will
+ * then really call "bogus_function()" instead!!!
+ *
+ * This feature will give you ample opportunities to get to know
+ * the taste of your foot when you stuff it into your mouth!!!
+ */
+}
/*
* Allocate space for a module.
asmlinkage int
sys_create_module(char *module_name, unsigned long size)
{
- int npages;
- void* addr;
- int len;
- char name[MOD_MAX_NAME];
- char *savename;
struct module *mp;
+ void* addr;
int error;
+ int npages;
+ int sspace = sizeof(struct module) + MOD_MAX_NAME;
+ char name[MOD_MAX_NAME];
if (!suser())
return -EPERM;
if (find_module(name) != NULL) {
return -EEXIST;
}
- len = strlen(name) + 1;
- if ((savename = (char*) kmalloc(len, GFP_KERNEL)) == NULL)
- return -ENOMEM;
- memcpy(savename, name, len);
- if ((mp = (struct module*) kmalloc(sizeof *mp, GFP_KERNEL)) == NULL) {
- kfree(savename);
+
+ if ((mp = (struct module*) kmalloc(sspace, GFP_KERNEL)) == NULL) {
return -ENOMEM;
}
+ strcpy((char *)(mp + 1), name); /* why not? */
+
npages = (size + sizeof (int) + 4095) / 4096;
if ((addr = vmalloc(npages * 4096)) == 0) {
- kfree_s(mp, sizeof *mp);
- kfree(savename);
+ kfree_s(mp, sspace);
return -ENOMEM;
}
- mp->name = savename;
+
+ mp->next = module_list;
+ mp->ref = NULL;
+ mp->symtab = NULL;
+ mp->name = (char *)(mp + 1);
mp->size = npages;
mp->addr = addr;
mp->state = MOD_UNINITIALIZED;
- * (int *) addr = 0; /* set use count to zero */
mp->cleanup = NULL;
- mp->next = module_list;
- module_list = mp;
- printk("module `%s' (%lu pages @ 0x%08lx) created\n",
- mp->name, (unsigned long) mp->size, (unsigned long) mp->addr);
+
+ * (int *) addr = 0; /* set use count to zero */
+ module_list = mp; /* link it in */
+
+ PRINTK(("module `%s' (%lu pages @ 0x%08lx) created\n",
+ mp->name, (unsigned long) mp->size, (unsigned long) mp->addr));
return (int) addr;
}
*/
asmlinkage int
sys_init_module(char *module_name, char *code, unsigned codesize,
- struct mod_routines *routines)
+ struct mod_routines *routines,
+ struct symbol_table *symtab)
{
struct module *mp;
+ struct symbol_table *newtab;
char name[MOD_MAX_NAME];
int error;
struct mod_routines rt;
if (!suser())
return -EPERM;
+
+ /* A little bit of protection... we "know" where the user stack is... */
+ if (symtab && ((unsigned long)symtab > 0xb0000000)) {
+ printk("warning: you are using an old insmod, no symbols will be inserted!\n");
+ symtab = NULL;
+ }
+
/*
* First reclaim any memory from dead modules that where not
* freed when deleted. Should I think be done by timers when
if ((error = get_mod_name(module_name, name)) != 0)
return error;
- printk( "initializing module `%s', %d (0x%x) bytes\n",
- name, codesize, codesize);
+ PRINTK(("initializing module `%s', %d (0x%x) bytes\n",
+ name, codesize, codesize));
memcpy_fromfs(&rt, routines, sizeof rt);
if ((mp = find_module(name)) == NULL)
return -ENOENT;
memcpy_fromfs((char *)mp->addr + sizeof (int), code, codesize);
memset((char *)mp->addr + sizeof (int) + codesize, 0,
mp->size * 4096 - (codesize + sizeof (int)));
- printk( " init entry @ 0x%08lx, cleanup entry @ 0x%08lx\n",
- (unsigned long) rt.init, (unsigned long) rt.cleanup);
+ PRINTK(( "module init entry = 0x%08lx, cleanup entry = 0x%08lx\n",
+ (unsigned long) rt.init, (unsigned long) rt.cleanup));
mp->cleanup = rt.cleanup;
+
+ /* update kernel symbol table */
+ if (symtab) { /* symtab == NULL means no new entries to handle */
+ struct internal_symbol *sym;
+ struct module_ref *ref;
+ int size;
+ int i;
+
+ if ((error = verify_area(VERIFY_READ, symtab, sizeof(int))))
+ return error;
+ memcpy_fromfs((char *)(&(size)), symtab, sizeof(int));
+
+ if ((newtab = (struct symbol_table*) kmalloc(size, GFP_KERNEL)) == NULL) {
+ return -ENOMEM;
+ }
+
+ if ((error = verify_area(VERIFY_READ, symtab, size)))
+ return error;
+ memcpy_fromfs((char *)(newtab), symtab, size);
+
+ /* relocate name pointers, index referred from start of table */
+ for (sym = &(newtab->symbol[0]), i = 0;
+ i < newtab->n_symbols; ++sym, ++i) {
+ sym->name += (long)newtab;
+ }
+ mp->symtab = newtab;
+
+ /* Update module references.
+ * On entry, from "insmod", ref->module points to
+ * the referenced module!
+ * Also, "sym" from above, points to the first ref entry!!!
+ */
+ for (ref = (struct module_ref *)sym, i = 0;
+ i < newtab->n_refs; ++ref, ++i) {
+ ref->next = ref->module->ref;
+ ref->module->ref = ref;
+ ref->module = mp;
+ }
+ }
+
if ((*rt.init)() != 0)
return -EBUSY;
mp->state = MOD_RUNNING;
+
return 0;
}
if (!suser())
return -EPERM;
+ /* else */
if (module_name != NULL) {
if ((error = get_mod_name(module_name, name)) != 0)
return error;
if ((mp = find_module(name)) == NULL)
return -ENOENT;
- if (GET_USE_COUNT(mp) != 0)
+ if ((mp->ref != NULL) || (GET_USE_COUNT(mp) != 0))
return -EBUSY;
if (mp->state == MOD_RUNNING)
(*mp->cleanup)();
return 0;
}
+
/*
* Copy the kernel symbol table to user space. If the argument is null,
* just return the size of the table.
+ *
+ * Note that the transient module symbols are copied _first_,
+ * in lifo order!!!
+ *
+ * The symbols to "insmod" are according to the "old" format: struct kernel_sym,
+ * which is actually quite handy for this purpose.
+ * Note that insmod inserts a struct symbol_table later on...
+ * (as that format is quite handy for the kernel...)
+ *
+ * For every module, the first (pseudo)symbol copied is the module name
+ * and the adress of the module struct.
+ * This lets "insmod" keep track of references, and build the array of
+ * struct module_refs in the symbol table.
+ * The format of the module name is "#module", so that "insmod" can easily
+ * notice when a module name comes along. Also, this will make it possible
+ * to use old versions of "insmod", albeit with reduced functionality...
+ * The "kernel" module has an empty name.
*/
asmlinkage int
sys_get_kernel_syms(struct kernel_sym *table)
{
- struct symbol {
- unsigned long addr;
- char *name;
- };
- extern int symbol_table_size;
- extern struct symbol symbol_table[];
- int i;
- struct symbol *from;
+ struct internal_symbol *from;
+ struct kernel_sym isym;
struct kernel_sym *to;
- struct kernel_sym sym;
+ struct module *mp = module_list;
+ int i;
+ int nmodsyms = 0;
+
+ for (mp = module_list; mp; mp = mp->next) {
+ if (mp->symtab && mp->symtab->n_symbols) {
+ /* include the count for the module name! */
+ nmodsyms += mp->symtab->n_symbols + 1;
+ }
+ }
if (table != NULL) {
- from = symbol_table;
to = table;
- i = verify_area(VERIFY_WRITE, to, symbol_table_size * sizeof *table);
- if (i)
+
+ if ((i = verify_area(VERIFY_WRITE, to, nmodsyms * sizeof(*table))))
return i;
- for (i = symbol_table_size ; --i >= 0 ; ) {
- sym.value = from->addr;
- strncpy(sym.name, from->name, sizeof sym.name);
- memcpy_tofs(to, &sym, sizeof sym);
- from++, to++;
+
+ /* copy all module symbols first (always LIFO order) */
+ for (mp = module_list; mp; mp = mp->next) {
+ if ((mp->state == MOD_RUNNING) &&
+ (mp->symtab != NULL) && (mp->symtab->n_symbols > 0)) {
+ /* magic: write module info as a pseudo symbol */
+ isym.value = (unsigned long)mp;
+ sprintf(isym.name, "#%s", mp->name);
+ memcpy_tofs(to, &isym, sizeof isym);
+ ++to;
+
+ for (i = mp->symtab->n_symbols,
+ from = mp->symtab->symbol;
+ i > 0; --i, ++from, ++to) {
+
+ isym.value = (unsigned long)from->addr;
+ strncpy(isym.name, from->name, sizeof isym.name);
+ memcpy_tofs(to, &isym, sizeof isym);
+ }
+ }
}
}
- return symbol_table_size;
+
+ return nmodsyms;
}
return mp;
}
+static void
+drop_refs(struct module *mp)
+{
+ struct module *step;
+ struct module_ref *prev;
+ struct module_ref *ref;
+
+ for (step = module_list; step; step = step->next) {
+ for (prev = ref = step->ref; ref; ref = prev->next) {
+ if (ref->module == mp) {
+ if (ref == step->ref)
+ step->ref = ref->next;
+ else
+ prev->next = ref->next;
+ break; /* every module only references once! */
+ }
+ else
+ prev = ref;
+ }
+ }
+}
/*
* Try to free modules which have been marked for deletion. Returns nonzero
while ((mp = *mpp) != NULL) {
if (mp->state != MOD_DELETED) {
mpp = &mp->next;
- } else if (GET_USE_COUNT(mp) != 0) {
- freeing_modules = 1;
- mpp = &mp->next;
- } else { /* delete it */
- *mpp = mp->next;
- vfree(mp->addr);
- kfree(mp->name);
- kfree_s(mp, sizeof *mp);
- did_deletion = 1;
+ } else {
+ if (GET_USE_COUNT(mp) != 0) {
+ freeing_modules = 1;
+ mpp = &mp->next;
+ } else { /* delete it */
+ *mpp = mp->next;
+ if (mp->symtab) {
+ if (mp->symtab->n_refs)
+ drop_refs(mp);
+ if (mp->symtab->size)
+ kfree_s(mp->symtab, mp->symtab->size);
+ }
+ vfree(mp->addr);
+ kfree_s(mp, sizeof(struct module) + MOD_MAX_NAME);
+ did_deletion = 1;
+ }
}
}
return did_deletion;
char *q;
int i;
struct module *mp;
+ struct module_ref *ref;
char size[32];
p = buf;
- for (mp = module_list ; mp ; mp = mp->next) {
+ /* Do not show the kernel pseudo module */
+ for (mp = module_list ; mp && mp->next; mp = mp->next) {
if (p - buf > 4096 - 100)
break; /* avoid overflowing buffer */
q = mp->name;
q = " (bad state)";
while (*q)
*p++ = *q++;
+
+ if ((ref = mp->ref) != NULL) {
+ *p++ = '\t';
+ *p++ = '[';
+ for (; ref; ref = ref->next) {
+ q = ref->module->name;
+ while (*q)
+ *p++ = *q++;
+ if (ref->next)
+ *p++ = ' ';
+ }
+ *p++ = ']';
+ }
*p++ = '\n';
}
return p - buf;
}
+
+
+/*
+ * Called by the /proc file system to return a current list of ksyms.
+ */
+int get_ksyms_list(char *buf)
+{
+ struct module *mp;
+ struct internal_symbol *sym;
+ int i;
+ char *p = buf;
+
+ for (mp = module_list; mp; mp = mp->next) {
+ if ((mp->state == MOD_RUNNING) &&
+ (mp->symtab != NULL) && (mp->symtab->n_symbols > 0)) {
+ for (i = mp->symtab->n_symbols,
+ sym = mp->symtab->symbol;
+ i > 0; --i, ++sym) {
+
+ if (p - buf > 4096 - 100) {
+ strcat(p, "...\n");
+ p += strlen(p);
+ return p - buf; /* avoid overflowing buffer */
+ }
+
+ if (mp->name[0]) {
+ sprintf(p, "%08lx %s\t[%s]\n",
+ (long)sym->addr, sym->name, mp->name);
+ }
+ else {
+ sprintf(p, "%08lx %s\n",
+ (long)sym->addr, sym->name);
+ }
+ p += strlen(p);
+ }
+ }
+ }
+
+ return p - buf;
+}
+++ /dev/null
-/*
- * ddi.c Implement the Device Driver Interface (DDI) routines.
- * Currently, this is only used by the NET layer of LINUX,
- * but it eventually might move to an upper directory of
- * the system.
- *
- * Version: @(#)ddi.c 1.0.5 04/22/93
- *
- * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
- *
- * For the moment I'm classifying DDI as 'dead'. However if/when Fred
- * produces a masterpiece of design DDI may get resurrected. With the
- * current kernel as modules work by Peter MacDonald they might be
- * redundant anyway. Thus I've removed all but the protocol initialise.
- *
- * We will end up with protocol initialisers and socket family initialisers.
- */
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/types.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/ddi.h>
-
-
-#undef DDI_DEBUG
-#ifdef DDI_DEBUG
-# define PRINTK(x) printk x
-#else
-# define PRINTK(x) /**/
-#endif
-
-
-extern struct ddi_proto protocols[]; /* network protocols */
-
-
-/*
- * This is the function that is called by a kernel routine during
- * system startup. Its purpose is to walk trough the "devices"
- * table (defined above), and to call all moduled defined in it.
- */
-void
-ddi_init(void)
-{
- struct ddi_proto *pro;
-
- PRINTK (("DDI: Starting up!\n"));
-
- /* Kick all configured protocols. */
- pro = protocols;
- while (pro->name != NULL)
- {
- (*pro->init)(pro);
- pro++;
- }
- /* We're all done... */
-}
rt=ip_rt_route(saddr, NULL,NULL);
if(rt!=NULL && (rt->rt_flags&RTF_WINDOW))
- sk->window_clamp=rt->rt_window;
+ newsk->window_clamp = rt->rt_window;
else
- sk->window_clamp=0;
+ newsk->window_clamp = 0;
if (sk->user_mss)
newsk->mtu = sk->user_mss;