Commit 4cb8ac91 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.0.17

parent 6d58893f
......@@ -1104,7 +1104,7 @@ interface. PD is the Motorola Public Domain Interface and ICD is the
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}
......
VERSION = 2
PATCHLEVEL = 0
SUBLEVEL = 16
SUBLEVEL = 17
ARCH = i386
......
/*
* 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 <linux/config.h>
#include <linux/types.h>
......@@ -408,9 +411,11 @@ static void check_prefetch (unsigned int index)
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 @@ static void set_prefetch_mode (unsigned int index, int mode)
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 @@ static void program_drive_counts (unsigned int index)
* 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 */
}
......
......@@ -4067,12 +4067,16 @@ static int floppy_grab_irq_and_dma(void)
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 @@ static void floppy_release_irq_and_dma(void)
return;
}
INT_ON;
MOD_DEC_USE_COUNT;
fd_disable_dma();
fd_free_dma();
fd_disable_irq();
......@@ -4131,6 +4134,7 @@ static void floppy_release_irq_and_dma(void)
if (floppy_tq.sync)
printk("task queue still active\n");
#endif
MOD_DEC_USE_COUNT;
}
......
......@@ -13,7 +13,7 @@
* labelled E2550UA or MK4015 or 2800F).
*/
#define VERSION "v4.5 Eberhard Moenkeberg <emoenke@gwdg.de>"
#define VERSION "v4.6 Eberhard Moenkeberg <emoenke@gwdg.de>"
/* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg <emoenke@gwdg.de>
*
......@@ -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 <rriggs@tesser.com>. 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 const char *major_name="sbpcd4";
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 infobuf[20];
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 @@ static void sbp_sleep(u_int time)
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 @@ static void flush_status(void)
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 @@ static int cmd_out_T(void)
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 @@ static int cmd_out_T(void)
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 @@ static int check_version(void)
}
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 @@ static int DiskInfo(void)
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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_trk0<D_S[d].n_first_track) return (-EINVAL);
if (ti.cdti_trk0>D_S[d].n_last_track) return (-EINVAL);
if (ti.cdti_trk0<D_S[d].n_first_track) RETURN_UP(-EINVAL);
if (ti.cdti_trk0>D_S[d].n_last_track) RETURN_UP(-EINVAL);
if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0;
if (ti.cdti_trk1>D_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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 (i<D_S[d].n_first_track||i>D_S[d].n_last_track) return (-EINVAL);
else if (i<D_S[d].n_first_track||i>D_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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
}
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
}
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
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 void sbp_transfer(struct request *req)
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 @@ static void DO_SBPCD_REQUEST(void)
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 @@ static void DO_SBPCD_REQUEST(void)
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 @@ static void DO_SBPCD_REQUEST(void)
}
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 @@ static int sbp_data(struct request *req)
#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;frame<D_S[d].sbp_read_frames&&!error_flag; frame++)
......@@ -4855,9 +4943,16 @@ static int sbp_data(struct request *req)
wait=8;
do
{
sbp_sleep(1);
OUT(CDo_sel_i_d,0);
i=inb(CDi_status);
if (teac==2)
{
if ((i=CDi_stat_loop_T()) == -1) break;
}
else
{
sbp_sleep(1);
OUT(CDo_sel_i_d,0);
i=inb(CDi_status);
}
if (!(i&s_not_data_ready))
{
OUT(CDo_sel_i_d,1);
......@@ -5018,22 +5113,26 @@ static int sbpcd_open(struct inode *ip, struct file *fp)
if (fp->f_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 @@ static int sbpcd_open(struct inode *ip, struct file *fp)
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 @@ static int sbpcd_open(struct inode *ip, struct file *fp)
#endif SAFE_MIXED
}
if (!st_spinning) cc_SpinUp();
return (0);
RETURN_UP(0);
}
/*==========================================================================*/
/*
......@@ -5108,6 +5207,7 @@ static void sbpcd_release(struct inode * ip, struct file * file)
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 @@ static void sbpcd_release(struct inode * ip, struct file * file)
#endif SAFE_MIXED
}
}
up(&ioctl_read_sem);
}
/*==========================================================================*/
/*
......@@ -5365,7 +5466,10 @@ int SBPCD_INIT(void)
}
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 @@ int SBPCD_INIT(void)
#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 @@ int SBPCD_INIT(void)
*/
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 @@ int SBPCD_INIT(void)
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)
{
......
......@@ -1433,34 +1433,34 @@ static int con_write(struct tty_struct * tty, int from_user,
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);
......
......@@ -311,7 +311,7 @@ int fdc_interrupt_wait(int time)
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... */
}
......
......@@ -771,7 +771,7 @@ fdc_isr(void)
}
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 {
......
......@@ -795,7 +795,7 @@ static int read_chan(struct tty_struct *tty, struct file *file,
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 @@ static int read_chan(struct tty_struct *tty, struct file *file,
}
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 @@ static int normal_select(struct tty_struct * tty, struct inode * inode,
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
......
......@@ -1349,7 +1349,7 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on)
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 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on)
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;
......
......@@ -90,7 +90,7 @@ extern void enable_irq(unsigned int);
"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 @@ extern void enable_irq(unsigned int);
"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) \
......
......@@ -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. Dont 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,10 +173,15 @@
#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
/*==========================================================================*/
/*
* DDI interface definitions
......
......@@ -260,8 +260,8 @@ struct task_struct {
#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) */
......
......@@ -161,6 +161,7 @@ extern void tcp_send_reset(unsigned long saddr, unsigned long daddr, struct tcph
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);
......
......@@ -978,10 +978,11 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
/*
* 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) &&
......
......@@ -325,35 +325,38 @@ void tcp_write_xmit(struct sock *sk)
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 @@ void tcp_write_xmit(struct sock *sk)
}
#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));
......@@ -1190,3 +1200,56 @@ void tcp_send_probe0(struct sock *sk)
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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment