VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 54
+SUBLEVEL = 55
ARCH = i386
/* Define the following if you don't like that your drives seek audibly
- * after a disk change
+ * after a disk change (but it may not work correctly for everybody)
*/
-#define SILENT_DC_CLEAR
+/* #define SILENT_DC_CLEAR */
/* End of configuration */
{ 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"CompaQ"}, /* 9 2.88MB 3.5" */
{ 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
- { 3360,21,2,80,0,0x1C,0x00,0xCF,0x6C,"H1680" }, /* 11 1.68MB 3.5" */
+ { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
{ 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
{ 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
{ 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
{ 1760,11,2,80,0,0x1C,0x09,0xCF,0x6C,"h880" }, /* 20 880KB 5.25" */
{ 2080,13,2,80,0,0x1C,0x01,0xCF,0x6C,"D1040" }, /* 21 1.04MB 3.5" */
{ 2240,14,2,80,0,0x1C,0x19,0xCF,0x6C,"D1120" }, /* 22 1.12MB 3.5" */
- { 3200,20,2,80,0,0x1C,0x20,0xCF,0x6C,"h1600" }, /* 23 1.6MB 5.25" */
- { 3520,22,2,80,0,0x1C,0x08,0xCF,0x6C,"H1760" }, /* 24 1.76MB 3.5" */
+ { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
+ { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
{ 3840,24,2,80,0,0x1C,0x20,0xCF,0x6C,"H1920" }, /* 25 1.92MB 3.5" */
{ 6400,40,2,80,0,0x25,0x5B,0xCF,0x6C,"E3200" }, /* 26 3.20MB 3.5" */
{ 7040,44,2,80,0,0x25,0x5B,0xCF,0x6C,"E3520" }, /* 27 3.52MB 3.5" */
{ 3680,23,2,80,0,0x1C,0x10,0xCF,0x6C,"H1840" }, /* 29 1.84MB 3.5" */
{ 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
- { 3200,20,2,80,0,0x1C,0x00,0xCF,0x6C,"H1600" }, /* 31 1.6MB 3.5" */
+ { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
};
#define NUMBER(x) (sizeof(x) / sizeof(*(x)))
debugt("recal interrupt need 1 recal:");
#endif
/* after a second recalibrate, we still haven't
- * reached track 0. Probably no drive */
- DRS->track = PROVEN_ABSENT;
- cont->done(0);
+ * reached track 0. Probably no drive. Raise an
+ * error, as failing immediately might upset
+ * computers possessed by the Devil :-) */
+ cont->error();
cont->redo();
return;
case NEED_2_RECAL:
int count,head_shift,track_shift;
raw_cmd.flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
- FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
+ /*FD_RAW_NEED_DISK |*/ FD_RAW_NEED_SEEK;
raw_cmd.rate = floppy->rate & 0x3;
raw_cmd.cmd_count = NR_F;
COMMAND = FM_MODE(floppy,FD_FORMAT);
* Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
* in the early extended-partition checks and added DM partitions
*
- * IDE IRQ-unmask & drive-id & multiple-mode code added by Mark Lord.
- *
- * Support for BIOS drive geometry translation added by Mark Lord.
- * -- hd.c no longer chokes on drives with "more than 16 heads".
+ * IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
+ * and general streamlining by mlord@bnr.ca (Mark Lord).
*/
#define DEFAULT_MULT_COUNT 0 /* set to 0 to disable multiple mode at boot */
#define RECAL_FREQ 4 /* Recalibrate every 4th retry */
#define MAX_HD 2
+#define STAT_OK (READY_STAT|SEEK_STAT)
+#define OK_STATUS(s) (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
+
static void recal_intr(void);
static void bad_rw_intr(void);
static void dump_status (char *msg, unsigned int stat)
{
unsigned long flags;
- char dev;
+ char devc;
- dev = CURRENT ? 'a' + DEVICE_NR(CURRENT->dev) : '?';
+ devc = CURRENT ? 'a' + DEVICE_NR(CURRENT->dev) : '?';
save_flags (flags);
sti();
- printk("hd%c: %s: status=0x%02x { ", dev, msg, stat & 0xff);
+ printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
if (stat & BUSY_STAT) printk("Busy ");
if (stat & READY_STAT) printk("DriveReady ");
if (stat & WRERR_STAT) printk("WriteFault ");
if (stat & INDEX_STAT) printk("Index ");
if (stat & ERR_STAT) printk("Error ");
printk("}\n");
- if (stat & ERR_STAT) {
- unsigned int err = inb(HD_ERROR);
- printk("hd%c: %s: error=0x%02x { ", dev, msg, err & 0xff);
- if (err & BBD_ERR) printk("BadSector ");
- if (err & ECC_ERR) printk("UncorrectableError ");
- if (err & ID_ERR) printk("SectorIdNotFound ");
- if (err & ABRT_ERR) printk("DriveStatusError ");
- if (err & TRK0_ERR) printk("TrackZeroNotFound ");
- if (err & MARK_ERR) printk("AddrMarkNotFound ");
+ if ((stat & ERR_STAT) == 0) {
+ hd_error = 0;
+ } else {
+ hd_error = inb(HD_ERROR);
+ printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
+ if (hd_error & BBD_ERR) printk("BadSector ");
+ if (hd_error & ECC_ERR) printk("UncorrectableError ");
+ if (hd_error & ID_ERR) printk("SectorIdNotFound ");
+ if (hd_error & ABRT_ERR) printk("DriveStatusError ");
+ if (hd_error & TRK0_ERR) printk("TrackZeroNotFound ");
+ if (hd_error & MARK_ERR) printk("AddrMarkNotFound ");
printk("}");
- if (err & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
- if (CURRENT)
- printk(", sector=%ld", CURRENT->sector);
+ if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
+ if (CURRENT)
+ printk(", sector=%ld", CURRENT->sector);
}
printk("\n");
}
restore_flags (flags);
}
-static int win_result(void)
+void check_status(void)
{
- int i=inb_p(HD_STATUS);
+ int i = inb_p(HD_STATUS);
- if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
- == (READY_STAT | SEEK_STAT)) {
- hd_error = 0;
- return 0; /* ok */
+ if (!OK_STATUS(i)) {
+ dump_status("check_status", i);
+ bad_rw_intr();
}
- dump_status("win_result", i);
- return 1;
}
-static int controller_busy(void);
-static int status_ok(void);
-
-static int controller_ready(unsigned int drive, unsigned int head)
+static int controller_busy(void)
{
- int retry = 100;
+ int retries = 100000;
+ unsigned char status;
do {
- if (controller_busy() & BUSY_STAT)
- return 0;
- outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
- if (status_ok())
- return 1;
- } while (--retry);
- return 0;
+ status = inb_p(HD_STATUS);
+ } while ((status & BUSY_STAT) && --retries);
+ return status;
}
static int status_ok(void)
unsigned char status = inb_p(HD_STATUS);
if (status & BUSY_STAT)
- return 1;
+ return 1; /* Ancient, but does it make sense??? */
if (status & WRERR_STAT)
return 0;
if (!(status & READY_STAT))
return 1;
}
-static int controller_busy(void)
+static int controller_ready(unsigned int drive, unsigned int head)
{
- int retries = 100000;
- unsigned char status;
+ int retry = 100;
do {
- status = inb_p(HD_STATUS);
- } while ((status & BUSY_STAT) && --retries);
- return status;
+ if (controller_busy() & BUSY_STAT)
+ return 0;
+ outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
+ if (status_ok())
+ return 1;
+ } while (--retry);
+ return 0;
}
static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
{
unsigned short port;
-#ifdef DEBUG
- if (drive>1 || head>15) {
- printk("bad drive mapping, trying to access drive=%d, cyl=%d, head=%d, sect=%d\n",
- drive, cyl, head, sect);
- panic("harddisk driver problem");
- }
-#endif
#if (HD_DELAY > 0)
while (read_timer() - last_req < HD_DELAY)
/* nothing */;
/*
* Early model Quantum drives go weird at this point,
* but doing a recalibrate seems to "fix" them.
- * (Doing a full reset confuses some newer model Quantums)
+ * (Doing a full reset confuses some other model Quantums)
*/
if (!strncmp(id->model, "QUANTUM", 7))
special_op[dev] = recalibrate[dev] = 1;
sti();
if (stat & (BUSY_STAT|ERR_STAT)) {
mult_req[dev] = mult_count[dev] = 0;
- dump_status("set multiple mode failed", stat);
+ dump_status("set multmode failed", stat);
} else {
if ((mult_count[dev] = mult_req[dev]))
printk (" hd%c: enabled %d-sector multiple mode\n",
for (i = 0; i < 500000 ; i++) {
c = inb_p(HD_STATUS);
- c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
- if (c == (READY_STAT | SEEK_STAT))
+ if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
return 0;
}
dump_status("reset timed out", c);
outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
for(i = 0; i < 1000; i++) nop();
if (drive_busy())
- printk("HD-controller still busy\n");
- if ((hd_error = inb(HD_ERROR)) != 1)
- printk("HD-controller reset failed: %02x\n",hd_error);
+ printk("hd: controller still busy\n");
+ else if ((hd_error = inb(HD_ERROR)) != 1)
+ printk("hd: controller reset failed: %02x\n",hd_error);
}
static void reset_hd(void)
reset = 0;
i = -1;
reset_controller();
- } else if (win_result()) {
- bad_rw_intr();
+ } else {
+ check_status();
if (reset)
goto repeat;
}
if (++i < NR_HD) {
+ special_op[i] = recalibrate[i] = 1;
if (unmask_intr[i]) {
unmask_intr[i] = DEFAULT_UNMASK_INTR;
printk("hd%c: reset irq-unmasking to %d\n",i+'a',
hd_request();
}
-
/*
* Ok, don't know what to do with the unexpected interrupts: on some machines
* doing a reset and a retry seems to result in an eternal loop. Right now I
dev = DEVICE_NR(CURRENT->dev);
if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
end_request(0);
- special_op[dev] += recalibrate[dev] = 1;
+ special_op[dev] = recalibrate[dev] = 1;
} else if (CURRENT->errors % RESET_FREQ == 0)
reset = 1;
else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
- special_op[dev] += recalibrate[dev] = 1;
+ special_op[dev] = recalibrate[dev] = 1;
/* Otherwise just retry */
}
return -1;
}
-#define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
-#define STAT_OK (READY_STAT | SEEK_STAT)
-
static void read_intr(void)
{
unsigned int dev = DEVICE_NR(CURRENT->dev);
i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
continue;
- if ((i & STAT_MASK) != STAT_OK)
+ if (!OK_STATUS(i))
break;
if (i & DRQ_STAT)
goto ok_to_read;
i = (CURRENT->nr_sectors -= nsect);
#ifdef DEBUG
- printk("hd%c: read: sectors(%ld-%ld), remaining=%ld, buffer=%08lx\n",
+ printk("hd%c: read: sectors(%ld-%ld), remaining=%ld, buffer=0x%08lx\n",
dev+'a', CURRENT->sector, CURRENT->sector+nsect,
- CURRENT->nr_sectors, (long) CURRENT->buffer+(nsect<<9));
+ CURRENT->nr_sectors, (unsigned long) CURRENT->buffer+(nsect<<9));
#endif
if ((CURRENT->current_nr_sectors -= nsect) <= 0)
end_request(1);
if (unmask_intr[dev])
sti();
- if (((i = inb_p(HD_STATUS)) & STAT_MASK) == STAT_OK) {
+ if (OK_STATUS(i=inb_p(HD_STATUS))) {
if (i & DRQ_STAT) {
if (WCURRENT.nr_sectors) {
multwrite(dev);
i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
continue;
- if ((i & STAT_MASK) != STAT_OK)
+ if (!OK_STATUS(i))
break;
if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
goto ok_to_write;
static void recal_intr(void)
{
- if (win_result())
- bad_rw_intr();
+ check_status();
#if (HD_DELAY > 0)
last_req = read_timer();
#endif
*/
static void hd_times_out(void)
{
+ unsigned int dev;
+
DEVICE_INTR = NULL;
- sti();
if (!CURRENT)
return;
+ disable_irq(HD_IRQ);
+ sti();
reset = 1;
- printk(KERN_DEBUG "HD timeout\n");
+ dev = DEVICE_NR(CURRENT->dev);
+ printk("hd%c: timeout\n", dev+'a');
if (++CURRENT->errors >= MAX_ERRORS) {
#ifdef DEBUG
- printk("hd : too many errors.\n");
+ printk("hd%c: too many errors\n", dev+'a');
#endif
end_request(0);
}
cli();
-
hd_request();
+ enable_irq(HD_IRQ);
+}
+
+int do_special_op (unsigned int dev)
+{
+ if (recalibrate[dev]) {
+ recalibrate[dev] = 0;
+ hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
+ return reset;
+ }
+ if (!identified[dev]) {
+ identified[dev] = 1;
+ unmask_intr[dev] = DEFAULT_UNMASK_INTR;
+ mult_req[dev] = DEFAULT_MULT_COUNT;
+ hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
+ return reset;
+ }
+ if (mult_req[dev] != mult_count[dev]) {
+ hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
+ return reset;
+ }
+ if (hd_info[dev].head > 16) {
+ printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
+ end_request(0);
+ }
+ special_op[dev] = 0;
+ return 1;
}
/*
- * The driver has been modified to enable interrupts a bit more: in order to
- * do this we first (a) disable the timeout-interrupt and (b) clear the
- * device-interrupt. This way the interrupts won't mess with out code (the
- * worst that can happen is that an unexpected HD-interrupt comes in and
- * sets the "reset" variable and starts the timer)
+ * The driver enables interrupts as much as possible. In order to do this,
+ * (a) the device-interrupt is disabled before entering hd_request(),
+ * and (b) the timeout-interrupt is disabled before the sti().
+ *
+ * Interrupts are still masked (by default) whenever we are exchanging
+ * data/cmds with a drive, because some drives seem to have very poor
+ * tolerance for latency during I/O. For devices which don't suffer from
+ * that problem (most don't), the unmask_intr[] flag can be set to unmask
+ * other interrupts during data/cmd transfers (by defining DEFAULT_UNMASK_INTR
+ * to 1, or by using "hdparm -u1 /dev/hd?" from the shell).
*/
static void hd_request(void)
{
- unsigned int block,dev;
- unsigned int sec,head,cyl,track;
- unsigned int nsect;
+ unsigned int dev, block, nsect, sec, track, head, cyl;
if (CURRENT && CURRENT->dev < 0) return;
-
if (DEVICE_INTR)
return;
repeat:
timer_active &= ~(1<<HD_TIMER);
sti();
INIT_REQUEST;
+ if (reset) {
+ cli();
+ reset_hd();
+ return;
+ }
dev = MINOR(CURRENT->dev);
block = CURRENT->sector;
nsect = CURRENT->nr_sectors;
- if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
+ if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
#ifdef DEBUG
- printk("hd : attempted read for sector %d past end of device at sector %d.\n",
- block, hd[dev].nr_sects);
+ if (dev >= (NR_HD<<6))
+ printk("hd: bad minor number: device=0x%04x\n", CURRENT->dev);
+ else
+ printk("hd%c: bad access: block=%d, count=%d\n",
+ (CURRENT->dev>>6)+'a', block, nsect);
#endif
end_request(0);
goto repeat;
}
block += hd[dev].start_sect;
dev >>= 6;
- sec = block % hd_info[dev].sect + 1;
+ if (special_op[dev]) {
+ if (do_special_op(dev))
+ goto repeat;
+ return;
+ }
+ sec = block % hd_info[dev].sect + 1;
track = block / hd_info[dev].sect;
- head = track % hd_info[dev].head;
- cyl = track / hd_info[dev].head;
+ head = track % hd_info[dev].head;
+ cyl = track / hd_info[dev].head;
#ifdef DEBUG
- printk("hd%c : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
- dev+'a', cyl, head, sec, CURRENT->buffer);
+ printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
+ dev+'a', (CURRENT->cmd == READ)?"read":"writ",
+ cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
#endif
if (!unmask_intr[dev])
cli();
- if (reset) {
- int i;
-
- for (i=0; i < NR_HD; i++)
- special_op[i] = recalibrate[i] = 1;
- cli(); /* better play it safe, as resets are the last resort */
- reset_hd();
- return;
- }
- if (special_op[dev]) { /* we use "special_op" to reduce overhead on r/w */
- if (recalibrate[dev]) {
- recalibrate[dev] = 0;
- hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
- if (reset)
- goto repeat;
- return;
- }
- if (!identified[dev]) {
- identified[dev] = 1;
- unmask_intr[dev] = DEFAULT_UNMASK_INTR;
- mult_req[dev] = DEFAULT_MULT_COUNT;
- hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
- if (reset)
- goto repeat;
- return;
- }
- if (mult_req[dev] != mult_count[dev]) {
- hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
- if (reset)
- goto repeat;
- return;
- }
- if (hd_info[dev].head > 16) {
- printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
- end_request(0);
- goto repeat;
- }
- --special_op[dev];
- } /* special_op[dev] */
if (CURRENT->cmd == READ) {
unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;
hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);
if (reset)
goto repeat;
-#ifdef DEBUG
- printk("hd%c: reading %d sectors(%ld-%ld), buffer=%08lx\n",
- dev+'a', nsect, CURRENT->sector,
- CURRENT->sector+nsect-1, (long) CURRENT->buffer);
-#endif
return;
}
if (CURRENT->cmd == WRITE) {
hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
if (reset)
goto repeat;
-#ifdef DEBUG
- printk("hd%c: writing %d sectors(%ld-%ld), buffer=%08lx\n",
- dev+'a', nsect, CURRENT->sector,
- CURRENT->sector+nsect-1, (long) CURRENT->buffer);
-#endif
if (wait_DRQ()) {
bad_rw_intr();
goto repeat;
if (mult_count[dev]) {
WCURRENT = *CURRENT;
multwrite(dev);
- } else {
+ } else
outsw(HD_DATA,CURRENT->buffer,256);
- }
return;
}
panic("unknown hd-command");
if (arg > max_mult[dev])
err = -EINVAL; /* out of range for device */
else if (mult_req[dev] != mult_count[dev]) {
- ++special_op[dev];
+ special_op[dev] = 1;
err = -EBUSY; /* busy, try again */
} else {
mult_req[dev] = arg;
- ++special_op[dev];
+ special_op[dev] = 1;
err = 0;
}
restore_flags(flags);
}
i = NR_HD;
while (i-- > 0) {
- hd[i<<6].nr_sects = 0;
- if (bios_info[i].head > 16) {
- /*
- * The newer E-IDE BIOSs handle drives larger than 1024
- * cylinders by increasing the number of logical heads
- * to keep the number of logical cylinders below the
- * sacred INT13 limit of 1024 (10 bits). If that is
- * what's happening here, we'll find out and correct
- * it later when "identifying" the drive.
- */
- printk("hd.c: IDE/ST-506 disk with more than 16 heads detected.\n");
- printk(" (hd%c: cyl=%d, sect=%d, head=%d)\n", i+'a',
- bios_info[i].cyl,
- bios_info[i].sect,
- bios_info[i].head);
- }
+ /*
+ * The newer E-IDE BIOSs handle drives larger than 1024
+ * cylinders by increasing the number of logical heads
+ * to keep the number of logical cylinders below the
+ * sacred INT13 limit of 1024 (10 bits). If that is
+ * what's happening here, we'll find out and correct
+ * it later when "identifying" the drive.
+ */
hd[i<<6].nr_sects = bios_info[i].head *
bios_info[i].sect * bios_info[i].cyl;
hd_ident_info[i] = (struct hd_driveid *) kmalloc(512,GFP_KERNEL);
}
if (NR_HD) {
if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd")) {
- printk("hd.c: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
+ printk("hd: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
NR_HD = 0;
}
}
unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
{
if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
- printk("Unable to get major %d for harddisk\n",MAJOR_NR);
+ printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
return mem_start;
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
return 0;
}
+void cleanup_module(void)
+{
+ if(MOD_IN_USE)
+ printk("lp: busy - remove delayed\n");
+ else
+ unregister_chrdev(LP_MAJOR,"lp");
+}
+
#endif
@echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h
@echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h
@echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h
- @echo \#define SOUND_CONFIG_DOMAIN \"`domainname`\" >> local.h
+ @if [ -x /bin/dnsdomainname ]; then \
+ echo \#define SOUND_CONFIG_DOMAIN \"`dnsdomainname`\"; \
+ else \
+ echo \#define SOUND_CONFIG_DOMAIN \"`domainname`\"; \
+ fi >> local.h
clrconf:
rm -f local.h .depend
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;
+ current->suid = current->euid = current->fsuid = bprm->e_uid;
+ current->sgid = current->egid = current->fsgid = bprm->e_gid;
/* Calling sys_brk effectively mmaps the pages that we need for the bss and break
sections */
#include <linux/ext_fs.h>
#include <linux/stat.h>
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
static int ext_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
struct dirent * dirent, int count)
{
unsigned int i;
+ unsigned int ret;
off_t offset;
char c;
struct buffer_head * bh;
return -EBADF;
if ((filp->f_pos & 7) != 0)
return -EBADF;
- while (filp->f_pos < inode->i_size) {
+ ret = 0;
+ while (!ret && filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
bh = ext_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0);
if (!bh) {
filp->f_pos += 1024-offset;
continue;
}
+ for (i = 0; i < 1024 && i < offset; ) {
+ de = (struct ext_dir_entry *) (bh->b_data + i);
+ if (!de->rec_len)
+ break;
+ i += de->rec_len;
+ }
+ offset = i;
de = (struct ext_dir_entry *) (offset + bh->b_data);
- while (offset < 1024 && filp->f_pos < inode->i_size) {
+ while (!ret && offset < 1024 && filp->f_pos < inode->i_size) {
if (de->rec_len < 8 || de->rec_len % 8 != 0 ||
de->rec_len < de->name_len + 8 ||
(de->rec_len + (off_t) filp->f_pos - 1) / 1024 > ((off_t) filp->f_pos / 1024)) {
put_fs_long(de->inode,&dirent->d_ino);
put_fs_byte(0,i+dirent->d_name);
put_fs_word(i,&dirent->d_reclen);
- brelse(bh);
- return i;
+ ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
+ break;
}
}
de = (struct ext_dir_entry *) ((char *) de
}
brelse(bh);
}
- return 0;
+ return ret;
}
#include <linux/sched.h>
#include <linux/stat.h>
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
static int ext2_dir_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
struct dirent * dirent, int count)
{
unsigned long offset, blk;
- int i, num;
+ int i, num, stored, dlen;
struct buffer_head * bh, * tmp, * bha[16];
struct ext2_dir_entry * de;
struct super_block * sb;
- int err;
-
+ int err, version;
+
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
sb = inode->i_sb;
- while (filp->f_pos < inode->i_size) {
- offset = filp->f_pos & (sb->s_blocksize - 1);
+
+ stored = 0;
+ bh = NULL;
+ offset = filp->f_pos & (sb->s_blocksize - 1);
+
+ while (count > 0 && !stored && filp->f_pos < inode->i_size) {
blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
bh = ext2_bread (inode, blk, 0, &err);
if (!bh) {
}
}
- de = (struct ext2_dir_entry *) (offset + bh->b_data);
- while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) {
+revalidate:
+ /* If the dir block has changed since the last call to
+ readdir(2), then we might be pointing to an invalid dirent
+ right now. Scan from the start of the block to make
+ sure. */
+ for (i = 0; i < sb->s_blocksize && i < offset; ) {
+ de = (struct ext2_dir_entry *) (bh->b_data + i);
+ /* It's too expensive to do a full dirent test
+ * each time round this loop, but we do have
+ * to test at least that it is non-zero. A
+ * failure will be detected in the dirent test
+ * below. */
+ if (de->rec_len < EXT2_DIR_REC_LEN(1))
+ break;
+ i += de->rec_len;
+ }
+ offset = i;
+ filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset;
+
+ while (count > 0 && filp->f_pos < inode->i_size
+ && offset < sb->s_blocksize) {
+ de = (struct ext2_dir_entry *) (bh->b_data + offset);
if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
bh, offset)) {
+ /* On error, skip the f_pos to the next block. */
+ filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
+ + sb->s_blocksize;
brelse (bh);
- return 0;
+ return stored;
}
- offset += de->rec_len;
- filp->f_pos += de->rec_len;
if (de->inode) {
- memcpy_tofs (dirent->d_name, de->name,
- de->name_len);
+ dlen = ROUND_UP(NAME_OFFSET(dirent)
+ + de->name_len + 1);
+ /* Old libc libraries always use a count of 1. */
+ if (count == 1 && !stored)
+ count = dlen;
+ if (count < dlen) {
+ count = 0;
+ break;
+ }
+
+ /* We might block in the next section
+ * if the data destination is
+ * currently swapped out. So, use a
+ * version stamp to detect whether or
+ * not the directory has been modified
+ * during the copy operation. */
+ version = inode->i_version;
+ i = de->name_len;
+ memcpy_tofs (dirent->d_name, de->name, i);
put_fs_long (de->inode, &dirent->d_ino);
- put_fs_byte (0, de->name_len + dirent->d_name);
- put_fs_word (de->name_len, &dirent->d_reclen);
+ put_fs_byte (0, dirent->d_name + i);
+ put_fs_word (i, &dirent->d_reclen);
+ put_fs_long (dlen, &dirent->d_off);
+ if (version != inode->i_version)
+ goto revalidate;
dcache_add(inode, de->name, de->name_len,
de->inode);
- i = de->name_len;
- brelse (bh);
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
- return i;
+
+ stored += dlen;
+ count -= dlen;
+ ((char *) dirent) += dlen;
}
- de = (struct ext2_dir_entry *) ((char *) de +
- de->rec_len);
+ offset += de->rec_len;
+ filp->f_pos += de->rec_len;
}
+ offset = 0;
brelse (bh);
}
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
- return 0;
+ return stored;
}
*/
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
dir->i_dirt = 1;
+ dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
*res_dir = de;
*err = 0;
goto start_up;
try_again:
- if (new_bh && new_de)
+ if (new_bh && new_de) {
ext2_delete_entry(new_de, new_bh);
+ new_dir->i_version = ++event;
+ }
brelse (old_bh);
brelse (new_bh);
brelse (dir_bh);
&retval);
if (!new_bh)
goto end_rename;
+ new_dir->i_version = ++event;
/*
* sanity checking before doing the rename - avoid races
*/
* ok, that's it
*/
new_de->inode = old_inode->i_ino;
- new_dir->i_version = ++event;
dcache_add(new_dir, new_de->name, new_de->name_len, new_de->inode);
retval = ext2_delete_entry (old_de, old_bh);
if (retval == -ENOENT)
\f
/* notation */
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
#define little_ushort(x) (*(unsigned short *) &(x))
typedef void nonconst;
case 0:
write_one_dirent(dirent, ".", 1, inode->i_ino, lc);
filp->f_pos = -1;
- return 1;
+ return ROUND_UP(NAME_OFFSET(dirent) + 2);
case -1:
write_one_dirent(dirent, "..", 2,
inode->i_hpfs_parent_dir, lc);
filp->f_pos = 1;
- return 2;
+ return ROUND_UP(NAME_OFFSET(dirent) + 3);
case -2:
return 0;
write_one_dirent(dirent, de->name, namelen, ino, lc);
brelse4(&qbh);
- return namelen;
+ return ROUND_UP(NAME_OFFSET(dirent) + namelen + 1);
}
}
#include <linux/sched.h>
#include <linux/locks.h>
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
static int isofs_readdir(struct inode *, struct file *, struct dirent *, int);
static struct file_operations isofs_dir_operations = {
put_fs_byte(0,i+dirent->d_name);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
- return i;
+ return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
}
}
/* We go here for any condition we cannot handle. We also drop through
#include <linux/minix_fs.h>
#include <linux/stat.h>
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
static int minix_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
static int minix_readdir(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
- unsigned int offset,i;
+ unsigned int offset,i,ret;
+ int version;
char c;
struct buffer_head * bh;
struct minix_dir_entry * de;
info = &inode->i_sb->u.minix_sb;
if (filp->f_pos & (info->s_dirsize - 1))
return -EBADF;
- while (filp->f_pos < inode->i_size) {
+ ret = 0;
+ while (!ret && filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
bh = minix_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0);
if (!bh) {
filp->f_pos += 1024-offset;
continue;
}
- while (offset < 1024 && filp->f_pos < inode->i_size) {
+ while (!ret && offset < 1024 && filp->f_pos < inode->i_size) {
de = (struct minix_dir_entry *) (offset + bh->b_data);
offset += info->s_dirsize;
filp->f_pos += info->s_dirsize;
+retry:
if (de->inode) {
for (i = 0; i < info->s_namelen; i++)
if ((c = de->name[i]) != 0)
else
break;
if (i) {
+ version = inode->i_version;
put_fs_long(de->inode,&dirent->d_ino);
put_fs_byte(0,i+dirent->d_name);
put_fs_word(i,&dirent->d_reclen);
- brelse(bh);
- return i;
+ if (version != inode->i_version)
+ goto retry;
+ ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
}
}
brelse(bh);
}
- return 0;
+ return ret;
}
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
for (i = 0; i < info->s_namelen ; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
+ dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
*res_dir = de;
break;
if (inode->i_nlink != 2)
printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
de->inode = 0;
+ dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
inode->i_nlink=0;
inode->i_dirt=1;
- dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_nlink--;
dir->i_dirt=1;
retval = 0;
end_rmdir:
inode->i_nlink=1;
}
de->inode = 0;
+ dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt = 1;
new_de->inode = old_inode->i_ino;
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
old_dir->i_dirt = 1;
+ old_dir->i_version = ++event;
new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
new_dir->i_dirt = 1;
+ new_dir->i_version = ++event;
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME;
#include <linux/stat.h>
#include <linux/string.h>
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
static int msdos_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
{
put_fs_long(MSDOS_ROOT_INO,&dirent->d_ino);
put_fs_byte(0,dirent->d_name+i);
put_fs_word(i,&dirent->d_reclen);
- return i;
+ return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
}
}
if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1)) return -ENOENT;
memcpy_tofs(dirent->d_name,bufname,i+1);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
- return i;
+ return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
}
}
}
#include <asm/segment.h> /* for fs functions */
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
static int nfs_dir_read(struct inode *, struct file *filp, char *buf,
int count);
static int nfs_readdir(struct inode *, struct file *, struct dirent *, int);
put_fs_long(entry->fileid, &dirent->d_ino);
put_fs_word(i, &dirent->d_reclen);
filp->f_pos = entry->cookie;
- return i;
+ return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
return 0;
}
new_f->f_count++;
current->files->fd[fd] = new_f;
- f->f_count--;
+ if (!--f->f_count)
+ iput(f->f_inode);
return 0;
}
#include <asm/segment.h>
/*
- * Count is not yet used: but we'll probably support reading several entries
- * at once in the future. Use count=1 in the library for future expansions.
+ * Count is now a supported feature, but currently only the ext2fs
+ * uses it. A count value of 1 is supported for compatibility with
+ * earlier libraries, but larger values are supported: count should
+ * indicate the total buffer space available for filling with dirents.
+ * The d_off entry in the dirents will then indicate the offset from
+ * each dirent to the next, and the return value will indicate the
+ * number of bytes written. All dirents will be written at
+ * word-aligned addresses. [sct Oct 1994]
*/
asmlinkage int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count)
{
}
if (tmp < 0)
return -EINVAL;
- file->f_pos = tmp;
- file->f_reada = 0;
+ if (tmp != file->f_pos) {
+ file->f_pos = tmp;
+ file->f_reada = 0;
+ }
return file->f_pos;
}
#include <linux/sysv_fs.h>
#include <linux/stat.h>
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
static int sysv_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
put_fs_byte(0,i+dirent->d_name);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
- return i;
+ return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
}
}
#include "xiafs_mac.h"
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
static int xiafs_dir_read(struct inode *, struct file *, char *, int);
static int xiafs_readdir(struct inode *, struct file *, struct dirent *, int);
static int xiafs_readdir(struct inode * inode,
struct file * filp, struct dirent * dirent, int count)
{
- u_int offset, i;
+ u_int offset, i,ret;
struct buffer_head * bh;
struct xiafs_direct * de;
return -EBADF;
if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb) - 1) )
return -EBADF;
- while (filp->f_pos < inode->i_size) {
+ ret = 0;
+ while (!ret && filp->f_pos < inode->i_size) {
offset = filp->f_pos & (XIAFS_ZSIZE(inode->i_sb) - 1);
bh = xiafs_bread(inode, filp->f_pos >> XIAFS_ZSIZE_BITS(inode->i_sb),0);
if (!bh) {
filp->f_pos += XIAFS_ZSIZE(inode->i_sb)-offset;
continue;
}
+ for (i = 0; i < XIAFS_ZSIZE(inode->i_sb) && i < offset; ) {
+ de = (struct xiafs_direct *) (bh->b_data + i);
+ if (!de->d_rec_len)
+ break;
+ i += de->d_rec_len;
+ }
+ offset = i;
de = (struct xiafs_direct *) (offset + bh->b_data);
- while (offset < XIAFS_ZSIZE(inode->i_sb) && filp->f_pos < inode->i_size) {
+
+ while (!ret && offset < XIAFS_ZSIZE(inode->i_sb) && filp->f_pos < inode->i_size) {
if (de->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes ||
de->d_rec_len < 12 ||
(char *)de+de->d_rec_len > XIAFS_ZSIZE(inode->i_sb)+bh->b_data ||
put_fs_byte(0,i+dirent->d_name);
put_fs_long(de->d_ino,&dirent->d_ino);
put_fs_word(i,&dirent->d_reclen);
- brelse(bh);
if (!IS_RDONLY (inode)) {
inode->i_atime=CURRENT_TIME;
inode->i_dirt=1;
}
- return i;
+ ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
+ break;
}
de = (struct xiafs_direct *) (offset + bh->b_data);
}
#define HDIO_SETUNMASKINTR 0x303
#define HDIO_GETMULTCOUNT 0x304
#define HDIO_SETMULTCOUNT 0x305
-#define HDIO_SETFEATURE 0x306
#define HDIO_GETIDENTITY 0x307
#endif
extern void start_tty(struct tty_struct * tty);
extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
extern int tty_register_driver(struct tty_driver *driver);
+extern int tty_unregister_driver(struct tty_driver *driver);
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen);
#include <linux/module.h>
#include <linux/termios.h>
#include <linux/tqueue.h>
+#include <linux/tty.h>
#include <linux/serial.h>
#ifdef CONFIG_INET
#include <linux/netdevice.h>
X(unregister_chrdev),
X(register_blkdev),
X(unregister_blkdev),
+ X(tty_register_driver),
+ X(tty_unregister_driver),
+ X(tty_std_termios),
/* block device driver support */
X(block_read),
* Matt Dillon : Yet more small nasties remove from the TCP code
* (Be very nice to this man if tcp finally works 100%) 8)
* Alan Cox : BSD accept semantics.
+ * Peter De Schrijver : ENOTCONN check missing in tcp_sendto().
*
*
* To Fix:
{
if (flags & ~(MSG_OOB|MSG_DONTROUTE))
return -EINVAL;
- if (addr_len < sizeof(*addr))
- return(-EINVAL);
+ if (!tcp_connected(sk->state))
+ return -ENOTCONN;
+ if (addr_len < sizeof(*addr))
+ return -EINVAL;
if (addr->sin_family && addr->sin_family != AF_INET)
- return(-EINVAL);
+ return -EINVAL;
if (addr->sin_port != sk->dummy_th.dest)
- return(-EISCONN);
+ return -EISCONN;
if (addr->sin_addr.s_addr != sk->daddr)
- return(-EISCONN);
- return(tcp_write(sk, from, len, nonblock, flags));
+ return -EISCONN;
+ return tcp_write(sk, from, len, nonblock, flags);
}
/* The +1 is not needed because the FIN takes up seq
is not read!!! */
if(skb->len > 0 && after(skb->h.th->seq + skb->len , sk->copied_seq))
- need_reset = 1;
+ need_reset = 0;
kfree_skb(skb, FREE_READ);
}
if(sk->debug)