diff -u --recursive --new-file v2.0.16/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v2.0.16/linux/Documentation/devices.tex Wed Jul 10 13:11:40 1996 +++ linux/Documentation/devices.tex Mon Sep 2 08:41:25 1996 @@ -1104,7 +1104,7 @@ commercial interface by P\&E. \begin{devicelist} -\major{54}{Electrocardiognosis Holter serial card} +\major{54}{}{char }{Electrocardiognosis Holter serial card} \minor{0}{/dev/holter0}{First Holter port} \minor{1}{/dev/holter1}{Second Holter port} \minor{2}{/dev/holter2}{Third Holter port} diff -u --recursive --new-file v2.0.16/linux/Makefile linux/Makefile --- v2.0.16/linux/Makefile Sun Sep 1 09:15:32 1996 +++ linux/Makefile Sun Sep 1 09:15:14 1996 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 0 -SUBLEVEL = 16 +SUBLEVEL = 17 ARCH = i386 diff -u --recursive --new-file v2.0.16/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c --- v2.0.16/linux/drivers/block/cmd640.c Sat Aug 17 21:19:26 1996 +++ linux/drivers/block/cmd640.c Mon Sep 2 08:41:25 1996 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cmd640.c Version 1.01 Aug 12, 1996 + * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) */ @@ -94,9 +94,12 @@ * Version 1.00 Mmm.. cannot depend on PCMD_ENA in all systems * Version 1.01 slow/fast devsel can be selected with "hdparm -p6/-p7" * ("fast" is necessary for 32bit I/O in some systems) + * Version 1.02 fix bug that resulted in slow "setup times" + * (patch courtesy of Zoltan Hidvegi) */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ +#define CMD640_PREFETCH_MASKS 1 #include #include @@ -408,9 +411,11 @@ drive->no_io_32bit = 1; drive->io_32bit = 0; } else { +#if CMD640_PREFETCH_MASKS drive->no_unmask = 1; - drive->no_io_32bit = 0; drive->unmask = 0; +#endif + drive->no_io_32bit = 0; } } @@ -454,8 +459,10 @@ cli(); b = get_cmd640_reg(reg); if (mode) { /* want prefetch on? */ +#if CMD640_PREFETCH_MASKS drive->no_unmask = 1; drive->unmask = 0; +#endif drive->no_io_32bit = 0; b &= ~prefetch_masks[index]; /* enable prefetch */ } else { @@ -556,9 +563,10 @@ * Convert setup_count to internal chipset representation */ switch (setup_count) { - case 4: setup_count = 0x00; - case 3: setup_count = 0x80; - case 2: setup_count = 0x40; + case 4: setup_count = 0x00; break; + case 3: setup_count = 0x80; break; + case 1: + case 2: setup_count = 0x40; break; default: setup_count = 0xc0; /* case 5 */ } diff -u --recursive --new-file v2.0.16/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.0.16/linux/drivers/block/floppy.c Sun Sep 1 09:15:32 1996 +++ linux/drivers/block/floppy.c Mon Sep 2 10:55:26 1996 @@ -4067,12 +4067,16 @@ if (fd_request_irq()) { DPRINT("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ); + MOD_DEC_USE_COUNT; + usage_count--; return -1; } if (fd_request_dma()) { DPRINT("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA); fd_free_irq(); + MOD_DEC_USE_COUNT; + usage_count--; return -1; } for (fdc = 0; fdc < N_FDC; fdc++) @@ -4098,7 +4102,6 @@ return; } INT_ON; - MOD_DEC_USE_COUNT; fd_disable_dma(); fd_free_dma(); fd_disable_irq(); @@ -4131,6 +4134,7 @@ if (floppy_tq.sync) printk("task queue still active\n"); #endif + MOD_DEC_USE_COUNT; } diff -u --recursive --new-file v2.0.16/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.0.16/linux/drivers/cdrom/sbpcd.c Sat Aug 17 21:19:26 1996 +++ linux/drivers/cdrom/sbpcd.c Sun Sep 1 09:14:25 1996 @@ -13,7 +13,7 @@ * labelled E2550UA or MK4015 or 2800F). */ -#define VERSION "v4.5 Eberhard Moenkeberg " +#define VERSION "v4.6 Eberhard Moenkeberg " /* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg * @@ -293,11 +293,15 @@ * ll_rw_blk.c). * "Check media change" without touching any drive. * + * 4.6 Use a semaphore to synchronize multi-activity; elaborated by Rob + * Riggs . At the moment, we simply block "read" + * against "ioctl" and vice versa. This could be refined further, but + * I guess with almost no performance increase. + * Experiments to speed up the CD-55A; again with help of Rob Riggs + * (to be true, he gave both, idea & code. ;-) * - * TODO * - * synchronize multi-activity - * (data + audio + ioctl + disk change, multiple drives) + * TODO * implement "read all subchannel data" (96 bytes per frame) * * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine @@ -571,9 +575,8 @@ static struct wait_queue *sbp_waitq = NULL; #endif FUTURE -/*==========================================================================*/ -#define SBP_BUFFER_FRAMES 8 /* driver's own read_ahead, data mode */ -/*==========================================================================*/ +static int teac=SBP_TEAC_SPEED; +static int buffers=SBP_BUFFER_FRAMES; static u_char family0[]="MATSHITA"; /* MKE CR-521, CR-522, CR-523 */ static u_char family1[]="CR-56"; /* MKE CR-562, CR-563 */ @@ -592,8 +595,11 @@ static u_char xa_head_buf[CD_XA_HEAD]; static u_char xa_tail_buf[CD_XA_TAIL]; +#if OLD_BUSY static volatile u_char busy_data=0; static volatile u_char busy_audio=0; /* true semaphores would be safer */ +#endif OLD_BUSY +static struct semaphore ioctl_read_sem = MUTEX; static u_long timeout; static volatile u_char timed_out_delay=0; static volatile u_char timed_out_data=0; @@ -828,6 +834,8 @@ sti(); } /*==========================================================================*/ +#define RETURN_UP(rc) {up(&ioctl_read_sem); return(rc);} +/*==========================================================================*/ /* * convert logical_block_address to m-s-f_number (3 bytes only) */ @@ -960,6 +968,57 @@ sbp_sleep(15*HZ/10); for (i=maxtim_data;i!=0;i--) inb(CDi_status); } +/*====================================================================*/ +/* + * CDi status loop for Teac CD-55A (Rob Riggs) + * + * This is needed because for some strange reason + * the CD-55A can take a real long time to give a + * status response. This seems to happen after we + * issue a READ command where a long seek is involved. + * + * I tried to ensure that we get max throughput with + * minimal busy waiting. We busy wait at first, then + * "switch gears" and start sleeping. We sleep for + * longer periods of time the longer we wait. + * + */ +static int CDi_stat_loop_T(void) +{ + int i, gear=1; + u_long timeout_1, timeout_2, timeout_3, timeout_4; + + timeout_1 = jiffies + HZ / 50; /* sbp_sleep(0) for a short period */ + timeout_2 = jiffies + HZ / 5; /* nap for no more than 200ms */ + timeout_3 = jiffies + 5 * HZ; /* sleep for up to 5s */ + timeout_4 = jiffies + 45 * HZ; /* long sleep for up to 45s. */ + do + { + i = inb(CDi_status); + if (!(i&s_not_data_ready)) return (i); + if (!(i&s_not_result_ready)) return (i); + switch(gear) + { + case 4: + sbp_sleep(HZ); + if (jiffies > timeout_4) gear++; + msg(DBG_TEA, "CDi_stat_loop_T: long sleep active.\n"); + break; + case 3: + sbp_sleep(HZ/10); + if (jiffies > timeout_3) gear++; + break; + case 2: + sbp_sleep(HZ/100); + if (jiffies > timeout_2) gear++; + break; + case 1: + sbp_sleep(0); + if (jiffies > timeout_1) gear++; + } + } while (gear < 5); + return -1; +} /*==========================================================================*/ static int CDi_stat_loop(void) { @@ -1290,8 +1349,20 @@ for (ntries=CMDT_TRIES;ntries>0;ntries--) { if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(HZ); /* fixme */ +#if 01 OUT(CDo_sel_i_d,1); - i=inb(CDi_status); +#endif 01 + if (teac==2) + { + if ((i=CDi_stat_loop_T()) == -1) break; + } + else + { +#if 0 + OUT(CDo_sel_i_d,1); +#endif 0 + i=inb(CDi_status); + } if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */ { OUT(CDo_sel_i_d,1); @@ -1384,7 +1455,8 @@ return (-D_S[d].error_state-400); } if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */ - sbp_sleep(HZ/10); + if ((teac==0)||(ntries<(CMDT_TRIES-5))) sbp_sleep(HZ/10); + else sbp_sleep(HZ/100); if (ntries>(CMDT_TRIES-50)) continue; msg(DBG_TEA,"cmd_out_T: next CMDT_TRIES (%02X): %d.\n", drvcmd[0], ntries-1); } @@ -3343,7 +3415,7 @@ } else if (famV_drive) { - if (j==100) D_S[d].drv_type=drv_at; + if ((j==100)||(j==150)) D_S[d].drv_type=drv_at; ask_mail(); /* hopefully we get some feedback by this */ } } @@ -3716,7 +3788,7 @@ return (i); } if (D_S[d].f_multisession) D_S[d].sbp_bufsiz=1; /* possibly a weird PhotoCD */ - else D_S[d].sbp_bufsiz=SBP_BUFFER_FRAMES; + else D_S[d].sbp_bufsiz=buffers; i=cc_ReadTocEntry(D_S[d].n_first_track); if (i<0) { @@ -3878,16 +3950,17 @@ msg(DBG_INF, "ioctl: bad device: %04X\n", inode->i_rdev); return (-ENXIO); /* no such drive */ } + down(&ioctl_read_sem); if (d!=i) switch_drive(i); #if 0 st=GetStatus(); - if (st<0) return (-EIO); + if (st<0) RETURN_UP(-EIO); if (!toc_valid) { i=DiskInfo(); - if (i<0) return (-EIO); /* error reading TOC */ + if (i<0) RETURN_UP(-EIO); /* error reading TOC */ } #endif @@ -3895,9 +3968,9 @@ switch (cmd) /* Sun-compatible */ { case DDIOCSDBG: /* DDI Debug */ - if (!suser()) return (-EPERM); + if (!suser()) RETURN_UP(-EPERM); i=sbpcd_dbg_ioctl(arg,1); - return (i); + RETURN_UP(i); case CDROMPAUSE: /* Pause the drive */ msg(DBG_IOC,"ioctl: CDROMPAUSE entered.\n"); @@ -3910,19 +3983,19 @@ case audio_playing: if (famL_drive) i=cc_ReadSubQ(); else i=cc_Pause_Resume(1); - if (i<0) return (-EIO); + if (i<0) RETURN_UP(-EIO); if (famL_drive) i=cc_Pause_Resume(1); else i=cc_ReadSubQ(); - if (i<0) return (-EIO); + if (i<0) RETURN_UP(-EIO); D_S[d].pos_audio_start=D_S[d].SubQ_run_tot; D_S[d].audio_state=audio_pausing; - return (0); + RETURN_UP(0); case audio_pausing: i=cc_Seek(D_S[d].pos_audio_start,1); - if (i<0) return (-EIO); - return (0); + if (i<0) RETURN_UP(-EIO); + RETURN_UP(0); default: - return (-EINVAL); + RETURN_UP(-EINVAL); } case CDROMRESUME: /* resume paused audio play */ @@ -3935,26 +4008,26 @@ i=cc_PlayAudio(D_S[d].pos_audio_start, D_S[d].pos_audio_end); else i=cc_Pause_Resume(3); - if (i<0) return (-EIO); + if (i<0) RETURN_UP(-EIO); D_S[d].audio_state=audio_playing; - return (0); + RETURN_UP(0); case CDROMPLAYMSF: msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n"); #if SAFE_MIXED - if (D_S[d].has_data>1) return (-EBUSY); + if (D_S[d].has_data>1) RETURN_UP(-EBUSY); #endif SAFE_MIXED if (D_S[d].audio_state==audio_playing) { i=cc_Pause_Resume(1); - if (i<0) return (-EIO); + if (i<0) RETURN_UP(-EIO); i=cc_ReadSubQ(); - if (i<0) return (-EIO); + if (i<0) RETURN_UP(-EIO); D_S[d].pos_audio_start=D_S[d].SubQ_run_tot; i=cc_Seek(D_S[d].pos_audio_start,1); } st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_msf)); - if (st) return (st); + if (st) RETURN_UP(st); memcpy_fromfs(&msf, (void *) arg, sizeof(struct cdrom_msf)); /* values come as msf-bin */ D_S[d].pos_audio_start = (msf.cdmsf_min0<<16) | @@ -3971,33 +4044,36 @@ msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); DriveReset(); D_S[d].audio_state=0; - return (-EIO); + RETURN_UP(-EIO); } D_S[d].audio_state=audio_playing; - return (0); + RETURN_UP(0); case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n"); #if SAFE_MIXED - if (D_S[d].has_data>1) return (-EBUSY); + if (D_S[d].has_data>1) RETURN_UP(-EBUSY); #endif SAFE_MIXED if (D_S[d].audio_state==audio_playing) { msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n"); - return (0); - return (-EINVAL); +#if 1 + RETURN_UP(0); /* just let us play on */ +#else + RETURN_UP(-EINVAL); /* play on, but say "error" */ +#endif } st=verify_area(VERIFY_READ,(void *) arg,sizeof(struct cdrom_ti)); if (st<0) { msg(DBG_IOX,"CDROMPLAYTRKIND: verify_area error.\n"); - return (st); + RETURN_UP(st); } memcpy_fromfs(&ti,(void *) arg,sizeof(struct cdrom_ti)); msg(DBG_IOX,"ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n", ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1); - if (ti.cdti_trk0D_S[d].n_last_track) return (-EINVAL); + if (ti.cdti_trk0D_S[d].n_last_track) RETURN_UP(-EINVAL); if (ti.cdti_trk1D_S[d].n_last_track) ti.cdti_trk1=D_S[d].n_last_track; D_S[d].pos_audio_start=D_S[d].TocBuffer[ti.cdti_trk0].address; @@ -4008,28 +4084,29 @@ msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); DriveReset(); D_S[d].audio_state=0; - return (-EIO); + RETURN_UP(-EIO); } D_S[d].audio_state=audio_playing; - return (0); + RETURN_UP(0); case CDROMREADTOCHDR: /* Read the table of contents header */ msg(DBG_IOC,"ioctl: CDROMREADTOCHDR entered.\n"); tochdr.cdth_trk0=D_S[d].n_first_track; tochdr.cdth_trk1=D_S[d].n_last_track; st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_tochdr)); - if (st) return (st); + if (st) RETURN_UP(st); memcpy_tofs((void *) arg, &tochdr, sizeof(struct cdrom_tochdr)); - return (0); + RETURN_UP(0); case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n"); st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry)); - if (st) return (st); + if (st) RETURN_UP(st); memcpy_fromfs(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry)); i=tocentry.cdte_track; if (i==CDROM_LEADOUT) i=D_S[d].n_last_track+1; - else if (iD_S[d].n_last_track) return (-EINVAL); + else if (iD_S[d].n_last_track) + RETURN_UP(-EINVAL); tocentry.cdte_adr=D_S[d].TocBuffer[i].ctl_adr&0x0F; tocentry.cdte_ctrl=(D_S[d].TocBuffer[i].ctl_adr>>4)&0x0F; tocentry.cdte_datamode=D_S[d].TocBuffer[i].format; @@ -4041,68 +4118,68 @@ } else if (tocentry.cdte_format==CDROM_LBA) /* blk required */ tocentry.cdte_addr.lba=msf2blk(D_S[d].TocBuffer[i].address); - else return (-EINVAL); + else RETURN_UP(-EINVAL); memcpy_tofs((void *) arg, &tocentry, sizeof(struct cdrom_tocentry)); - return (0); + RETURN_UP(0); case CDROMRESET: /* hard reset the drive */ msg(DBG_IOC,"ioctl: CDROMRESET entered.\n"); i=DriveReset(); D_S[d].audio_state=0; - return (i); + RETURN_UP(i); case CDROMSTOP: /* Spin down the drive */ msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n"); #if SAFE_MIXED - if (D_S[d].has_data>1) return (-EBUSY); + if (D_S[d].has_data>1) RETURN_UP(-EBUSY); #endif SAFE_MIXED i=cc_Pause_Resume(1); D_S[d].audio_state=0; - return (i); + RETURN_UP(i); case CDROMSTART: /* Spin up the drive */ msg(DBG_IOC,"ioctl: CDROMSTART entered.\n"); cc_SpinUp(); D_S[d].audio_state=0; - return (0); + RETURN_UP(0); case CDROMEJECT: msg(DBG_IOC,"ioctl: CDROMEJECT entered.\n"); if (fam0_drive) return (0); - if (D_S[d].open_count>1) return (-EBUSY); + if (D_S[d].open_count>1) RETURN_UP(-EBUSY); i=UnLockDoor(); D_S[d].open_count=-9; /* to get it locked next time again */ i=cc_SpinDown(); msg(DBG_IOX,"ioctl: cc_SpinDown returned %d.\n", i); msg(DBG_TEA,"ioctl: cc_SpinDown returned %d.\n", i); - if (i<0) return (-EIO); + if (i<0) RETURN_UP(-EIO); D_S[d].CD_changed=0xFF; D_S[d].diskstate_flags=0; D_S[d].audio_state=0; - return (0); + RETURN_UP(0); case CDROMEJECT_SW: msg(DBG_IOC,"ioctl: CDROMEJECT_SW entered.\n"); - if (fam0_drive) return (0); + if (fam0_drive) RETURN_UP(0); D_S[d].f_eject=arg; - return (0); + RETURN_UP(0); case CDROMVOLCTRL: /* Volume control */ msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n"); st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl)); - if (st) return (st); + if (st) RETURN_UP(st); memcpy_fromfs(&volctrl,(char *) arg,sizeof(volctrl)); D_S[d].vol_chan0=0; D_S[d].vol_ctrl0=volctrl.channel0; D_S[d].vol_chan1=1; D_S[d].vol_ctrl1=volctrl.channel1; i=cc_SetVolume(); - return (0); + RETURN_UP(0); case CDROMVOLREAD: /* read Volume settings from drive */ msg(DBG_IOC,"ioctl: CDROMVOLREAD entered.\n"); st=verify_area(VERIFY_WRITE,(void *)arg,sizeof(volctrl)); - if (st) return (st); + if (st) RETURN_UP(st); st=cc_GetVolume(); if (st<0) return (st); volctrl.channel0=D_S[d].vol_ctrl0; @@ -4110,15 +4187,16 @@ volctrl.channel2=0; volctrl.channel2=0; memcpy_tofs((void *)arg,&volctrl,sizeof(volctrl)); - return (0); + RETURN_UP(0); case CDROMSUBCHNL: /* Get subchannel info */ msg(DBG_IOS,"ioctl: CDROMSUBCHNL entered.\n"); - if ((st_spinning)||(!subq_valid)) { i=cc_ReadSubQ(); - if (i<0) return (-EIO); - } + if ((st_spinning)||(!subq_valid)) { + i=cc_ReadSubQ(); + if (i<0) RETURN_UP(-EIO); + } st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl)); - if (st) return (st); + if (st) RETURN_UP(st); memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl)); switch (D_S[d].audio_state) { @@ -4156,27 +4234,27 @@ SC.cdsc_adr,SC.cdsc_ctrl, SC.cdsc_trk,SC.cdsc_ind, SC.cdsc_absaddr,SC.cdsc_reladdr); - return (0); + RETURN_UP(0); case CDROMREADMODE1: msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n"); #if SAFE_MIXED - if (D_S[d].has_data>1) return (-EBUSY); + if (D_S[d].has_data>1) RETURN_UP(-EBUSY); #endif SAFE_MIXED cc_ModeSelect(CD_FRAMESIZE); cc_ModeSense(); D_S[d].mode=READ_M1; - return (0); + RETURN_UP(0); case CDROMREADMODE2: /* not usable at the moment */ msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n"); #if SAFE_MIXED - if (D_S[d].has_data>1) return (-EBUSY); + if (D_S[d].has_data>1) RETURN_UP(-EBUSY); #endif SAFE_MIXED cc_ModeSelect(CD_FRAMESIZE_RAW1); cc_ModeSense(); D_S[d].mode=READ_M2; - return (0); + RETURN_UP(0); case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */ msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n"); @@ -4193,11 +4271,11 @@ } else msg(DBG_INF,"audio buffer size: %d frames.\n",D_S[d].sbp_audsiz); } - return (D_S[d].sbp_audsiz); + RETURN_UP(D_S[d].sbp_audsiz); case CDROMREADAUDIO: { /* start of CDROMREADAUDIO */ - int i=0, j=0, frame, block; + int i=0, j=0, frame, block=0; u_int try=0; u_long timeout; u_char *p; @@ -4208,27 +4286,27 @@ int error_flag; msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n"); - if (fam0_drive) return (-EINVAL); - if (famL_drive) return (-EINVAL); - if (famV_drive) return (-EINVAL); - if (famT_drive) return (-EINVAL); + if (fam0_drive) RETURN_UP(-EINVAL); + if (famL_drive) RETURN_UP(-EINVAL); + if (famV_drive) RETURN_UP(-EINVAL); + if (famT_drive) RETURN_UP(-EINVAL); #if SAFE_MIXED - if (D_S[d].has_data>1) return (-EBUSY); + if (D_S[d].has_data>1) RETURN_UP(-EBUSY); #endif SAFE_MIXED - if (D_S[d].aud_buf==NULL) return (-EINVAL); + if (D_S[d].aud_buf==NULL) RETURN_UP(-EINVAL); i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio)); - if (i) return (i); + if (i) RETURN_UP(i); memcpy_fromfs(&read_audio, (void *) arg, sizeof(struct cdrom_read_audio)); - if (read_audio.nframes>D_S[d].sbp_audsiz) return (-EINVAL); + if (read_audio.nframes>D_S[d].sbp_audsiz) RETURN_UP(-EINVAL); i=verify_area(VERIFY_WRITE, read_audio.buf, read_audio.nframes*CD_FRAMESIZE_RAW); - if (i) return (i); + if (i) RETURN_UP(i); if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */ block=msf2lba(&read_audio.addr.msf.minute); else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */ block=read_audio.addr.lba; - else return (-EINVAL); + else RETURN_UP(-EINVAL); #if 000 i=cc_SetSpeed(speed_150,0,0); if (i) msg(DBG_AUD,"read_audio: SetSpeed error %d\n", i); @@ -4236,8 +4314,10 @@ msg(DBG_AUD,"read_audio: lba: %d, msf: %06X\n", block, blk2msf(block)); msg(DBG_AUD,"read_audio: before cc_ReadStatus.\n"); +#if OLD_BUSY while (busy_data) sbp_sleep(HZ/10); /* wait a bit */ busy_audio=1; +#endif OLD_BUSY error_flag=0; for (data_tries=5; data_tries>0; data_tries--) { @@ -4400,43 +4480,45 @@ cc_ModeSelect(CD_FRAMESIZE); cc_ModeSense(); D_S[d].mode=READ_M1; +#if OLD_BUSY busy_audio=0; +#endif OLD_BUSY if (data_tries == 0) { msg(DBG_AUD,"read_audio: failed after 5 tries.\n"); - return (-8); + RETURN_UP(-EIO); } msg(DBG_AUD,"read_audio: successful return.\n"); - return (0); + RETURN_UP(0); } /* end of CDROMREADAUDIO */ case CDROMMULTISESSION: /* tell start-of-last-session */ msg(DBG_IOC,"ioctl: CDROMMULTISESSION entered.\n"); st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession)); - if (st) return (st); + if (st) RETURN_UP(st); memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession)); if (ms_info.addr_format==CDROM_MSF) /* MSF-bin requested */ lba2msf(D_S[d].lba_multi,&ms_info.addr.msf.minute); else if (ms_info.addr_format==CDROM_LBA) /* lba requested */ ms_info.addr.lba=D_S[d].lba_multi; - else return (-EINVAL); + else RETURN_UP(-EINVAL); if (D_S[d].f_multisession) ms_info.xa_flag=1; /* valid redirection address */ else ms_info.xa_flag=0; /* invalid redirection address */ memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession)); msg(DBG_MUL,"ioctl: CDROMMULTISESSION done (%d, %08X).\n", ms_info.xa_flag, ms_info.addr.lba); - return (0); + RETURN_UP(0); case BLKRASET: - if(!suser()) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - if(arg > 0xff) return -EINVAL; + if(!suser()) RETURN_UP(-EACCES); + if(!(inode->i_rdev)) RETURN_UP(-EINVAL); + if(arg > 0xff) RETURN_UP(-EINVAL); read_ahead[MAJOR(inode->i_rdev)] = arg; - return (0); + RETURN_UP(0); default: msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); - return (-EINVAL); + RETURN_UP(-EINVAL); } /* end switch(cmd) */ } /*==========================================================================*/ @@ -4489,6 +4571,7 @@ static inline void sbpcd_end_request(struct request *req, int uptodate) { req->next=CURRENT; CURRENT=req; + up(&ioctl_read_sem); end_request(uptodate); } /*==========================================================================*/ @@ -4528,6 +4611,7 @@ CURRENT=req->next; /* task can fuck it up GTL */ sti(); + down(&ioctl_read_sem); if (req->rq_status == RQ_INACTIVE) sbpcd_end_request(req, 0); if (req -> sector == -1) @@ -4545,8 +4629,10 @@ kdevname(req->rq_dev)); goto err_done; } +#if OLD_BUSY while (busy_audio) sbp_sleep(HZ); /* wait a bit */ busy_data=1; +#endif OLD_BUSY if (D_S[i].audio_state==audio_playing) goto err_done; if (d!=i) switch_drive(i); @@ -4612,7 +4698,9 @@ } err_done: +#if OLD_BUSY busy_data=0; +#endif OLD_BUSY #ifdef DEBUG_GTL printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n", xnr, req, req->sector, req->nr_sectors, jiffies); @@ -4753,8 +4841,8 @@ #if LONG_TIMING max_latency=9*HZ; #else - if (D_S[d].f_multisession) max_latency=9*HZ; - else max_latency=3*HZ; + if (D_S[d].f_multisession) max_latency=15*HZ; + else max_latency=5*HZ; #endif duration=jiffies; for (frame=0;framef_mode & 2) return -EROFS; + down(&ioctl_read_sem); switch_drive(i); i=cc_ReadError(); flags_cmd_out |= f_respo2; - cc_ReadStatus(); /* command: give 1-byte status */ + cc_ReadStatus(); /* command: give 1-byte status */ i=ResponseStatus(); if (famT_drive&&(i<0)) { cc_DriveReset(); i=ResponseStatus(); +#if 0 + sbp_sleep(HZ); +#endif 0 i=ResponseStatus(); } if (i<0) { msg(DBG_INF,"sbpcd_open: ResponseStatus timed out (%d).\n",i); - return (-EIO); /* drive doesn't respond */ + RETURN_UP(-EIO); /* drive doesn't respond */ } if (famT_drive) msg(DBG_TEA,"sbpcd_open: ResponseStatus=%02X\n", i); if (!st_door_closed) @@ -5065,7 +5164,7 @@ cc_SpinDown(); /* eject tray */ } #endif - return (-ENXIO); + RETURN_UP(-ENXIO); } /* * try to keep an "open" counter here and lock the door if 0->1. @@ -5092,7 +5191,7 @@ #endif SAFE_MIXED } if (!st_spinning) cc_SpinUp(); - return (0); + RETURN_UP(0); } /*==========================================================================*/ /* @@ -5108,6 +5207,7 @@ msg(DBG_INF, "release: bad device: %04X\n", ip->i_rdev); return; } + down(&ioctl_read_sem); switch_drive(i); /* * try to keep an "open" counter here and unlock the door if 1->0. @@ -5132,6 +5232,7 @@ #endif SAFE_MIXED } } + up(&ioctl_read_sem); } /*==========================================================================*/ /* @@ -5365,7 +5466,10 @@ } if (port_index>0) - msg(DBG_INF, "You should configure sbpcd.h for your hardware.\n"); + { + msg(DBG_INF, "You should read linux/Documentation/cdrom/sbpcd\n"); + msg(DBG_INF, "and then configure sbpcd.h for your hardware.\n"); + } check_datarate(); msg(DBG_INI,"check_datarate done.\n"); @@ -5450,7 +5554,7 @@ #endif MODULE } blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - read_ahead[MAJOR_NR] = SBP_BUFFER_FRAMES * (CD_FRAMESIZE / 512); + read_ahead[MAJOR_NR] = buffers * (CD_FRAMESIZE / 512); request_region(CDo_command,4,major_name); @@ -5466,7 +5570,7 @@ */ D_S[j].aud_buf=NULL; D_S[j].sbp_audsiz=0; - D_S[j].sbp_bufsiz=SBP_BUFFER_FRAMES; + D_S[j].sbp_bufsiz=buffers; if (D_S[j].drv_type&drv_fam1) if (READ_AUDIO>0) D_S[j].sbp_audsiz=READ_AUDIO; D_S[j].sbp_buf=(u_char *) vmalloc(D_S[j].sbp_bufsiz*CD_FRAMESIZE); @@ -5476,7 +5580,7 @@ return -EIO; } #ifdef MODULE - msg(DBG_INF,"data buffer size: %d frames.\n",SBP_BUFFER_FRAMES); + msg(DBG_INF,"data buffer size: %d frames.\n",buffers); #endif MODULE if (D_S[j].sbp_audsiz>0) { diff -u --recursive --new-file v2.0.16/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.0.16/linux/drivers/char/console.c Thu Aug 29 19:15:14 1996 +++ linux/drivers/char/console.c Mon Sep 2 08:41:25 1996 @@ -1433,34 +1433,34 @@ tc = translate[toggle_meta ? (c|0x80) : c]; } - /* If the original code was < 32 we only allow a - * glyph to be displayed if the code is not normally - * used (such as for cursor movement) or if the - * disp_ctrl mode has been explicitly enabled. - * Note: ESC is *never* allowed to be displayed as - * that would disable all escape sequences! - * To display font position 0x1B, go into UTF mode - * and display character U+F01B, or change the mapping. - */ - ok = (tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS - : CTRL_ACTION) >> c) & 1)))); + /* If the original code was a control character we + * only allow a glyph to be displayed if the code is + * not normally used (such as for cursor movement) or + * if the disp_ctrl mode has been explicitly enabled. + * Certain characters (as given by the CTRL_ALWAYS + * bitmap) are always displayed as control characters, + * as the console would be pretty useless without + * them; to display an arbitrary font position use the + * direct-to-font zone in UTF-8 mode. + */ + ok = tc && (c >= 32 || + (!utf && !(((disp_ctrl ? CTRL_ALWAYS + : CTRL_ACTION) >> c) & 1))) + && (c != 127 || disp_ctrl); if (vc_state == ESnormal && ok) { /* Now try to find out how to display it */ tc = conv_uni_to_pc(tc); - if ( tc == -4 ) - { - /* If we got -4 (not found) then see if we have - defined a replacement character (U+FFFD) */ - tc = conv_uni_to_pc(0xfffd); - } - else if ( tc == -3 ) - { - /* Bad hash table -- hope for the best */ - tc = c; - } + if ( tc == -4 ) { + /* If we got -4 (not found) then see if we have + defined a replacement character (U+FFFD) */ + tc = conv_uni_to_pc(0xfffd); + } else if ( tc == -3 ) { + /* Bad hash table -- hope for the best */ + tc = c; + } if (tc & ~console_charmask) - continue; /* Conversion failed */ + continue; /* Conversion failed */ if (need_wrap) { cr(currcons); diff -u --recursive --new-file v2.0.16/linux/drivers/char/ftape/fdc-io.c linux/drivers/char/ftape/fdc-io.c --- v2.0.16/linux/drivers/char/ftape/fdc-io.c Fri Apr 12 09:49:34 1996 +++ linux/drivers/char/ftape/fdc-io.c Sun Sep 1 09:14:45 1996 @@ -311,7 +311,7 @@ int current_blocked = current->blocked; static int resetting = 0; - if (wait_intr) { + if (waitqueue_active(&wait_intr)) { TRACE(1, "error: nested call"); return -EIO; /* return error... */ } diff -u --recursive --new-file v2.0.16/linux/drivers/char/ftape/fdc-isr.c linux/drivers/char/ftape/fdc-isr.c --- v2.0.16/linux/drivers/char/ftape/fdc-isr.c Fri Apr 12 09:49:34 1996 +++ linux/drivers/char/ftape/fdc-isr.c Sun Sep 1 09:14:45 1996 @@ -771,7 +771,7 @@ } seek_completed = 1; fdc_mode = fdc_idle; - } else if (!wait_intr) { + } else if (!waitqueue_active(&wait_intr)) { if (expected_stray_interrupts == 0) { TRACE(2, "unexpected stray interrupt"); } else { diff -u --recursive --new-file v2.0.16/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.0.16/linux/drivers/char/n_tty.c Wed Jul 24 10:49:53 1996 +++ linux/drivers/char/n_tty.c Sun Sep 1 09:14:45 1996 @@ -795,7 +795,7 @@ current->timeout = (unsigned long) -1; if (time) tty->minimum_to_wake = 1; - else if (!tty->read_wait || + else if (!waitqueue_active(&tty->read_wait) || (tty->minimum_to_wake > minimum)) tty->minimum_to_wake = minimum; } else { @@ -907,7 +907,7 @@ } remove_wait_queue(&tty->read_wait, &wait); - if (!tty->read_wait) + if (!waitqueue_active(&tty->read_wait)) tty->minimum_to_wake = minimum; current->state = TASK_RUNNING; @@ -991,7 +991,7 @@ return 1; if (tty_hung_up_p(file)) return 1; - if (!tty->read_wait) { + if (!waitqueue_active(&tty->read_wait)) { if (MIN_CHAR(tty) && !TIME_CHAR(tty)) tty->minimum_to_wake = MIN_CHAR(tty); else diff -u --recursive --new-file v2.0.16/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.0.16/linux/drivers/char/tty_io.c Wed Jul 24 10:53:39 1996 +++ linux/drivers/char/tty_io.c Sun Sep 1 09:14:45 1996 @@ -1349,7 +1349,7 @@ return retval; if (on) { - if (!tty->read_wait) + if (!waitqueue_active(&tty->read_wait)) tty->minimum_to_wake = 1; if (filp->f_owner == 0) { if (tty->pgrp) @@ -1358,7 +1358,7 @@ filp->f_owner = current->pid; } } else { - if (!tty->fasync && !tty->read_wait) + if (!tty->fasync && !waitqueue_active(&tty->read_wait)) tty->minimum_to_wake = N_TTY_BUF_SIZE; } return 0; diff -u --recursive --new-file v2.0.16/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h --- v2.0.16/linux/include/asm-i386/irq.h Thu Aug 29 19:15:14 1996 +++ linux/include/asm-i386/irq.h Sun Sep 1 10:53:04 1996 @@ -90,7 +90,7 @@ "outb %al,$0x21\n\t" \ "jmp 1f\n" \ "1:\tjmp 1f\n" \ - "1:\tmovb $0x60+"#nr",%al\n\t" \ + "1:\tmovb $0xE0+"#nr",%al\n\t" \ "outb %al,$0x20\n\t" #define ACK_SECOND(mask,nr) \ @@ -102,11 +102,11 @@ "outb %al,$0xA1\n\t" \ "jmp 1f\n" \ "1:\tjmp 1f\n" \ - "1:\tmovb $0x60+"#nr",%al\n\t" \ + "1:\tmovb $0xE0+"#nr",%al\n\t" \ "outb %al,$0xA0\n\t" \ "jmp 1f\n" \ "1:\tjmp 1f\n" \ - "1:\tmovb $0x62,%al\n\t" \ + "1:\tmovb $0xE2,%al\n\t" \ "outb %al,$0x20\n\t" #define UNBLK_FIRST(mask) \ diff -u --recursive --new-file v2.0.16/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h --- v2.0.16/linux/include/linux/sbpcd.h Sat Aug 17 21:19:29 1996 +++ linux/include/linux/sbpcd.h Sun Sep 1 09:14:25 1996 @@ -134,16 +134,38 @@ /* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */ #define READ_AUDIO 0 +/* Optimizations for the Teac CD-55A drive read performance. + * SBP_TEAC_SPEED can be changed here, or one can set the + * variable "teac" when loading as a module. + * Valid settings are: + * 0 - very slow - the recommended "DISTRIBUTION 1" setup. + * 1 - 2x performance with little overhead. No busy waiting. + * 2 - 4x performance with 5ms overhead per read. Busy wait. + * + * Setting SBP_TEAC_SPEED or the variable 'teac' to anything + * other than 0 may cause problems. If you run into them, first + * change SBP_TEAC_SPEED back to 0 and see if your drive responds + * normally. If yes, you are "allowed" to report your case - to help + * me with the driver, not to solve your hassle. Donīt mail if you + * simply are stuck into your own "tuning" experiments, you know? + */ +#define SBP_TEAC_SPEED 1 + /*==========================================================================*/ /*==========================================================================*/ /* - * nothing to change below here if you are not experimenting + * nothing to change below here if you are not fully aware what you're doing */ #ifndef _LINUX_SBPCD_H #define _LINUX_SBPCD_H /*==========================================================================*/ /*==========================================================================*/ +/* + * driver's own read_ahead, data mode + */ +#define SBP_BUFFER_FRAMES 8 + #define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */ #undef FUTURE #undef SAFE_MIXED @@ -151,9 +173,14 @@ #define TEST_UPC 0 #define SPEA_TEST 0 #define TEST_STI 0 +#define OLD_BUSY 0 #undef PATH_CHECK #ifndef SOUND_BASE #define SOUND_BASE 0 +#endif +#if DISTRIBUTION +#undef SBP_TEAC_SPEED +#define SBP_TEAC_SPEED 0 #endif /*==========================================================================*/ /* diff -u --recursive --new-file v2.0.16/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.0.16/linux/include/linux/sched.h Sun Sep 1 09:15:33 1996 +++ linux/include/linux/sched.h Mon Sep 2 08:55:09 1996 @@ -260,8 +260,8 @@ #define PF_DUMPCORE 0x00000200 /* dumped core */ #define PF_SIGNALED 0x00000400 /* killed by a signal */ -#define PF_STARTING 0x00000100 /* being created */ -#define PF_EXITING 0x00000200 /* getting shut down */ +#define PF_STARTING 0x00000002 /* being created */ +#define PF_EXITING 0x00000004 /* getting shut down */ #define PF_USEDFPU 0x00100000 /* Process used the FPU this quantum (SMP only) */ #define PF_DTRACE 0x00200000 /* delayed trace (used on m68k) */ diff -u --recursive --new-file v2.0.16/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.0.16/linux/include/net/tcp.h Thu Jul 25 20:31:57 1996 +++ linux/include/net/tcp.h Mon Sep 2 09:00:29 1996 @@ -161,6 +161,7 @@ extern void tcp_enqueue_partial(struct sk_buff *, struct sock *); extern struct sk_buff * tcp_dequeue_partial(struct sock *); +extern void tcp_shrink_skb(struct sock *,struct sk_buff *,u32); /* tcp_input.c */ extern void tcp_cache_zap(void); diff -u --recursive --new-file v2.0.16/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.0.16/linux/net/ipv4/tcp_input.c Mon Aug 5 10:13:56 1996 +++ linux/net/ipv4/tcp_input.c Mon Sep 2 08:41:24 1996 @@ -978,10 +978,11 @@ /* * Maybe we can take some stuff off of the write queue, * and put it onto the xmit queue. - * FIXME: (?) There is bizarre case being tested here, to check if + * There is bizarre case being tested here, to check if * the data at the head of the queue ends before the start of - * the sequence we already ACKed. This does not appear to be - * a case that can actually occur. Why are we testing it? + * the sequence we already ACKed. This is not an error, + * it can occur when we send a packet directly off of the write_queue + * in a zero window probe. */ if (!skb_queue_empty(&sk->write_queue) && diff -u --recursive --new-file v2.0.16/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.0.16/linux/net/ipv4/tcp_output.c Sun Sep 1 09:15:34 1996 +++ linux/net/ipv4/tcp_output.c Mon Sep 2 08:41:24 1996 @@ -325,35 +325,38 @@ skb_unlink(skb); /* - * See if we really need to send the packet. + * See if we really need to send the whole packet. */ - if (before(skb->end_seq, sk->rcv_ack_seq +1)) - { + if (before(skb->end_seq, sk->rcv_ack_seq +1)) { /* - * This is acked data. We can discard it. This - * cannot currently occur. + * This is acked data. We can discard it. + * This implies the packet was sent out + * of the write queue by a zero window probe. */ sk->retransmits = 0; kfree_skb(skb, FREE_WRITE); if (!sk->dead) sk->write_space(sk); - } - else - { + } else { struct tcphdr *th; struct iphdr *iph; int size; -/* - * put in the ack seq and window at this point rather than earlier, - * in order to keep them monotonic. We really want to avoid taking - * back window allocations. That's legal, but RFC1122 says it's frowned on. - * Ack and window will in general have changed since this packet was put - * on the write queue. - */ + iph = skb->ip_hdr; th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2)); + + /* See if we need to shrink the leading packet on + * the retransmit queue. Strictly speaking, we + * should never need to do this, but some buggy TCP + * implementations get confused if you send them + * a packet that contains both old and new data. (Feh!) + * Soooo, we have this uglyness here. + */ + if (after(sk->rcv_ack_seq,skb->seq+th->syn+th->fin)) + tcp_shrink_skb(sk,skb,sk->rcv_ack_seq); + size = skb->len - (((unsigned char *) th) - skb->data); #ifndef CONFIG_NO_PATH_MTU_DISCOVERY if (size > sk->mtu - sizeof(struct iphdr)) @@ -363,6 +366,13 @@ } #endif +/* + * put in the ack seq and window at this point rather than earlier, + * in order to keep them monotonic. We really want to avoid taking + * back window allocations. That's legal, but RFC1122 says it's frowned on. + * Ack and window will in general have changed since this packet was put + * on the write queue. + */ th->ack_seq = htonl(sk->acked_seq); th->window = htons(tcp_select_window(sk)); @@ -1189,4 +1199,57 @@ sk->retransmits++; sk->prot->retransmits ++; tcp_reset_xmit_timer (sk, TIME_PROBE0, sk->rto); +} + +/* + * Remove the portion of a packet that has already been sent. + * Needed to deal with buggy TCP implementations that can't deal + * with seeing a packet that contains some data that has already + * been received. + */ +void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack) +{ + struct iphdr *iph; + struct tcphdr *th; + unsigned char *old, *new; + unsigned long len; + int diff; + + /* + * Recover the buffer pointers + */ + + iph = (struct iphdr *)skb->ip_hdr; + th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2)); + + /* how much data are we droping from the tcp frame */ + diff = ack - skb->seq; + /* how much data are we keeping in the tcp frame */ + len = (skb->end_seq - (th->fin + th->syn)) - ack; + + /* pointers to new start of remaining data, and old start */ + new = (unsigned char *)th + th->doff*4; + old = new+diff; + + /* Update our starting seq number */ + skb->seq = ack; + th->seq = htonl(ack); + iph->tot_len = htons(ntohs(iph->tot_len)-diff); + + /* Get the partial checksum for the IP options */ + if (th->doff*4 - sizeof(*th) > 0) + skb->csum = csum_partial((void *)(th+1), + th->doff*4-sizeof(*th),0); + else + skb->csum = 0; + + /* Copy the good data down and get it's checksum */ + skb->csum = csum_partial_copy((void *)old,(void *)new,len,skb->csum); + + /* shorten the skb */ + skb_trim(skb,skb->len-diff); + + /* Checksum the shrunk buffer */ + tcp_send_check(th, sk->saddr, sk->daddr, + th->doff * 4 + len , skb); }