Beispiel #1
0
BOOLEAN
HwMidiRead(
    IN    PMIDI_INFO MidiInfo,
    OUT   PUCHAR Byte
)
/*++

Routine Description :

    Read a midi byte from the MPU

Arguments :

    MidiInfo - Midi parameters

Return Value :

    BOOL success/falure

--*/
{
    PSOUND_HARDWARE pHw;

    pHw = MidiInfo->HwContext;

    if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) {  // do we have data waiting (bit 7 clear)?
        *Byte = INPORT(pHw, MPU_DATA_PORT);
        return TRUE;
    } else {
        return FALSE;
    }
}
Beispiel #2
0
BOOLEAN 
mpuDumpBufferNoLock(
  PSOUND_HARDWARE pHw
)
/*++

Routine Description:

    Dumps the contents of the hardware buffer and discard it.
    Assume the hardware is already locked!

Arguments:

    pHw - pointer to the device extension data

Return Value:

    TRUE if we succeed.

--*/
{
  int Count = 0;
  int i;


  // dump the current hardware midi input
  while(Count < 2048) // we should have no more than this
  {
    for(i = 1000; i > 0; i--)
    {
      if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) {  // do we have data waiting (bit 7 clear)?
          INPORT(pHw, MPU_DATA_PORT);  // read and just discard the byte
          Count++;
          break;
      }
      KeStallExecutionProcessor(1);
    }

    // if we waited this long, we don't have anymore data to dump
    if(i == 0)
      break;
  }

  dprintf1(("Hardware buffer dump byte count %x", (ULONG)Count));
  
  return TRUE;  // always
}
Beispiel #3
0
BOOLEAN
mpuWrite(
    PSOUND_HARDWARE pHw,
    UCHAR value
)
/*++

Routine Description:

    Write a command or data to the MPU

Arguments:

    pHw - Pointer to the device extension data
    value - the value to be written

Return Value:

    TRUE if written correctly , FALSE otherwise

--*/
{
    ULONG uCount;

    ASSERT(pHw->Key == HARDWARE_KEY);

    uCount = 100;

    while (uCount--) {
        int InnerCount;

        HwEnter(pHw);

        //
        // Inner count loop protects against dynamic deadlock with
        // midi.
        //

        for (InnerCount = 0; InnerCount < 10; InnerCount++) {
            if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x40)) {  // is it ok to send data (bit 6 clear)? - drude
                OUTPORT(pHw, MPU_DATA_PORT, value);
                break;
            }
            KeStallExecutionProcessor(1); // 1 us
        }

        HwLeave(pHw);

        if (InnerCount < 10) {
            return TRUE;
        }
    }

    dprintf1(("mpuWrite:Failed to write %x to mpu", (ULONG)value));

    return FALSE;
}
Beispiel #4
0
BOOLEAN
mpuWriteNoLock(
    PSOUND_HARDWARE pHw,
    UCHAR value
)
/*++

Routine Description:

    Write a command or data to the MPU.  The call assumes the
    caller has acquired the spin lock

Arguments:

    pHw - Pointer to the device extension data
    value - the value to be written

Return Value:

    TRUE if written correctly , FALSE otherwise

--*/
{
    int uCount;

    ASSERT(pHw->Key == HARDWARE_KEY);

    uCount = 1000;

    while (uCount--) {
        if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x40)) {  // is it ok to send data (bit 6 clear)? - drude
            OUTPORT(pHw, MPU_DATA_PORT, value);
            break;
        }
        KeStallExecutionProcessor(1); // 1 us
    }

    if (uCount >= 0) {
        return TRUE;
    }

    dprintf1(("mpuWriteNoLock:Failed to write %x to mpu", (ULONG)value));

    return FALSE;
}
Beispiel #5
0
int vixConfigPlayback(vidix_playback_t *info)
{
	int src_w, drw_w;
	int src_h, drw_h;
	int hscale,vscale;
	long base0;
	int y_pitch = 0, uv_pitch = 0;
	int protect=0;
	int layout=0;
	unsigned int i;

	if(!is_supported_fourcc(info->fourcc))
		return -1;

	src_w = info->src.w;
	src_h = info->src.h;

	drw_w = info->dest.w;
	drw_h = info->dest.h;

	switch(info->fourcc)
	{
		case IMGFMT_YUY2:
		case IMGFMT_BGR16:
			y_pitch = (src_w*2 + 15) & ~15;
			uv_pitch = 0;
			YOffs=VOffs=UOffs=info->offset.y = info->offset.v = info->offset.u = 0;
			info->frame_size = y_pitch*src_h;
			layout=0x0; /* packed */
			break;
		case IMGFMT_YV12:
		case IMGFMT_I420:
			y_pitch = (src_w+15) & ~15;
			uv_pitch = ((src_w/2)+7) & ~7;
			YOffs=info->offset.y = 0;
			VOffs=info->offset.v = y_pitch*src_h;
			UOffs=info->offset.u = info->offset.v+(uv_pitch)*(src_h/2);
			info->frame_size = y_pitch*src_h + 2*uv_pitch*(src_h/2);
			layout=0x1; /* planar, 4:1:1 */
			break;
		case IMGFMT_YVU9:
			y_pitch = (src_w+15) & ~15;
			uv_pitch = ((src_w/4)+3) & ~3;
			YOffs=info->offset.y = 0;
			VOffs=info->offset.v = y_pitch*src_h;
			UOffs=info->offset.u = info->offset.v+(uv_pitch)*(src_h/4);
			info->frame_size = y_pitch*src_h + 2*uv_pitch*(src_h/4);
			layout=0x51; /* planar, 16:1:1 */
			break;
	}

	/* Assume we have 2 MB to play with */
	info->num_frames = 0x200000 / info->frame_size;
	if(info->num_frames > VID_PLAY_MAXFRAMES)
		info->num_frames = VID_PLAY_MAXFRAMES;

	/* Start at 6 MB. Let's hope it's not in use. */
	base0 = 0x600000;
	info->dga_addr = cyberblade_mem + base0;

	info->dest.pitch.y = 16;
	info->dest.pitch.u = 16;
	info->dest.pitch.v = 16;

	for(i = 0; i < info->num_frames; i++)
	{
		info->offsets[i] = info->frame_size * i;
		frames[i] = base0+info->offsets[i];
	}

	OUTPORT8(0x3d4,0x39);
	OUTPORT8(0x3d5,INPORT(0x3d5)|1);

	SRINB(0x0b); /* Select new mode */

	/* Unprotect hardware registers... */
	protect=SRINB(0x11);
	SROUTB(0x11, 0x92);

	SROUTB(0x57, 0xc0); /* Playback key function */
	SROUTB(0x21, 0x34); /* Signature control */
	SROUTB(0x37, 0x30); /* Video key mode */

        vixSetGrKeys(&cyberblade_grkey);

	/* compute_scale_factor(&src_w, &drw_w, &shrink, &zoom); */
	{
		int HTotal,VTotal,HSync,VSync,Overflow,HDisp,VDisp;
		int HWinStart,VWinStart;
		int tx1,ty1,tx2,ty2;

		HTotal=CRINB(0x00);
		HSync=CRINB(0x04);
		VTotal=CRINB(0x06);
		VSync=CRINB(0x10);
		Overflow=CRINB(0x07);
		HTotal <<=3;
		HSync <<=3;
		VTotal |= (Overflow & 1) <<8;
		VTotal |= (Overflow & 0x20) <<4;
		VTotal +=4;
		VSync |= (Overflow & 4) <<6;
		VSync |= (Overflow & 0x80) <<2;

		if(CRINB(0xd1)&0x80)
		{
			int TVHTotal,TVVTotal,TVHSyncStart,TVVSyncStart,TVOverflow;
			LOGWRITE("[cyberblade] Using TV-CRTC\n");

    			HDisp=(1+CRINB(0x01))*8;
    			VDisp=1+CRINB(0x12);
    			Overflow=CRINB(0x07);
    			VDisp |= (Overflow & 2) <<7;
    			VDisp |= (Overflow & 0x40) << 3;
 
    			TVHTotal=CRINB(0xe0)*8;
    			TVVTotal=CRINB(0xe6);
    			TVOverflow=CRINB(0xe7);
    			if(TVOverflow&0x20) TVVTotal|=512;
    			if(TVOverflow&0x01) TVVTotal|=256;
    			TVHTotal+=40; TVVTotal+=2;
 
    			TVHSyncStart=CRINB(0xe4)*8;
    			TVVSyncStart=CRINB(0xf0);
    			if(TVOverflow&0x80) TVVSyncStart|=512;
			if(TVOverflow&0x04) TVVSyncStart|=256;
 
			HWinStart=(TVHTotal-HDisp)&15;
			HWinStart|=(HTotal-HDisp)&15;
			HWinStart+=(TVHTotal-TVHSyncStart)-49;
		}
		else
		{
			LOGWRITE("[cyberblade] Using Standard CRTC\n");
			HWinStart=(HTotal-HSync)+15;
		}
                VWinStart=(VTotal-VSync)-8;

		printf("[cyberblade] HTotal: 0x%x, HSStart: 0x%x\n",HTotal,HSync); 
		printf("  VTotal: 0x%x, VStart: 0x%x\n",VTotal,VSync);
		tx1=HWinStart+info->dest.x;
		ty1=VWinStart+info->dest.y;
		tx2=tx1+info->dest.w;
		ty2=ty1+info->dest.h;

		CROUTW(0x86,tx1);
		CROUTW(0x88,ty1);
		CROUTW(0x8a,tx2);
		CROUTW(0x8c,ty2+3);
	}

	if(src_w==drw_w)
		hscale=0;
	else if(src_w<drw_w)
	{
		hscale=((src_w<<10)/(drw_w-2)) & 0x1fff;
	}
	else
	{
		hscale=0x8000 | ((((src_w/drw_w)-1)&7)<<10) | (((drw_w<<10)/src_w) & 0x3ff);
	}

	vscale=(src_h<<10)/(drw_h);
	if(drw_h<src_h)
		vscale=0x8000|((drw_h<<10)/(src_h));

	/* Write scale factors to hardware */

	CROUTW(0x80,hscale); /* Horizontal Scale */
	CROUTW(0x82,vscale); /* Vertical Scale */

	/* Now set the start address and data layout */
	{
		int lb = (y_pitch+2) >> 2;
		CROUTB(0x95, ((lb & 0x100)>>1) | 0x08 ); /* Linebuffer level bit 8 & threshold */
		CROUTB(0x96, (lb & 0xFF)); /* Linebuffer level */

		CROUTB(0x97, 0x00); /* VDE Flags */
		CROUTB(0xBA, 0x00); /* Chroma key */
		CROUTB(0xBB, 0x00); /* Chroma key */
		CROUTB(0xBC, 0xFF); /* Chroma key */
		CROUTB(0xBD, 0xFF); /* Chroma key */
		CROUTB(0xBE, 0x04); /* Capture control */

		if(src_w > 384)
			layout|=4; /* 2x line buffers */
		SROUTB(0x97, layout);

		CROUTW(0x90,y_pitch); /* Y Bytes per row */
		SROUTW(0x9A,uv_pitch); /* UV Bytes per row */

		switch(info->fourcc)
		{
			case IMGFMT_BGR16:
				CROUTB(0x8F, 0x24); /* VDE Flags - Edge Recovery & CSC Bypass */
				CROUTB(0xBF, 0x02); /* Video format - RGB16 */
				SROUTB(0xBE, 0x0); /* HSCB disabled */
				break;
			default:
				CROUTB(0x8F, 0x20); /* VDE Flags - Edge Recovery */
				CROUTB(0xBF, 0x00); /* Video format - YUV */
				SROUTB(0xBE, 0x00); /* HSCB disable - was 0x03*/
				break;
		}

		CROUTB(0x92, ((base0+info->offset.y) >> 3) &0xff); /* Lower 8 bits of start address */
		CROUTB(0x93, ((base0+info->offset.y) >> 11) &0xff); /* Mid 8 bits of start address */
		CROUTB(0x94, ((base0+info->offset.y) >> 19) &0xf); /* Upper 4 bits of start address */
		SROUTB(0x80, ((base0+info->offset.v) >> 3) &0xff); /* Lower 8 bits of start address */
		SROUTB(0x81, ((base0+info->offset.v) >> 11) &0xff); /* Mid 8 bits of start address */
		SROUTB(0x82, ((base0+info->offset.v) >> 19) &0xf); /* Upper 4 bits of start address */
		SROUTB(0x83, ((base0+info->offset.u) >> 3) &0xff); /* Lower 8 bits of start address */
		SROUTB(0x84, ((base0+info->offset.u) >> 11) &0xff); /* Mid 8 bits of start address */
		SROUTB(0x85, ((base0+info->offset.u) >> 19) &0xf); /* Upper 4 bits of start address */
	}

	vixPlaybackSetEq(&equal);

	/* Protect hardware registers again */
	SROUTB(0x11, protect);
	return 0;
}
/*========================================================= 
Name: pwm_wave_gen
Description:
This thread outputs the PWM duty cycle through the GPIO to
generate square wave. 
*=========================================================*/
void pwm_wave_gen(unsigned int pwm_period)
{	
unsigned int i = 0;

/* Configure GPIO18 as PWM1 output (ALT 5) to generate square wave */
INPORT(18u);
PORT_CONFIG(18u, 2u);

/* Configure PWM clock */
/* Stop the PWM first before changing the clock */
PWM_CTL1 = 0x00u;
usleep(10u);

/* Stop the PWM clock; ENAB=0 */
PWM_CLK_CTL = 0x5A000001u;
usleep(110u);

/* Wait till busy flag is cleared */
while ((PWM_CLK_CTL & 0x80u) != 0u);

/* Set the clock divider */
PWM_CLK_DIV = (0x5A000000u) | (1u << 12u);
usleep(10u);

/* Wait till busy flag is cleared */
while ((PWM_CLK_CTL & 0x80u) != 0u);
usleep(10u);

/* Start the clock; ENAB=1 */
PWM_CLK_CTL = 0x5A000011u;
usleep(10u);

/*
Example:
PWM Base Clock Frequency = 19.2 MHz, Clock Divider = 32,
Range = 1024. Hence PWM clock = 19.2MHz/32 = 600kHz or 1.7us;
PWM period: 600kHz/1024 = 585.9375Hz or 1.7ms
PWM duty cycle = (DATA/1024) * 585.9375Hz
Duty cycle 50% = 512/1024 * 585.9375Hz = 292.96875Hz or 0.85ms ON/OFF 
*/

/* Configure PWM1, Enable, PWM mode, Polarity:0, Data register used
   Mark:Space used */
PWM_CTL1 = 0x81u;
usleep(10u);

/* Set period of the PWM output */
PWM_RNG1 = pwm_period; /* 75Hz; 1024 = 10 bit resolution */
usleep(10u);

for (i = 0; i < 3; i++)
{
	/* Check PWM is transmitting */		
	if ((PWM_STA1 & 0x200u) == 0x200u)
	{
		/* Set duty cycle */
		PWM_DAT1 = PWM_RNG1/2;	
	}
		
	/* Generate the PWM pulse for 240ms */
	usleep(240000);
	
	/* Inter frame signal for 2 seconds */
	PWM_DAT1 = 0u;	
	sleep(2);
}

/* Stop the PWM; ENAB=0 */
PWM_CTL1 = 0x80u;
usleep(10u);

/* Tri state output port */
INPORT(18u);
}
Beispiel #7
0
NTSTATUS
SoundCardInstanceInit(
    IN   PWSTR RegistryPathName,
    IN   PVOID Context
)
{
    /*
    ** Instance data
    */

    PSOUND_CARD_INSTANCE CardInstance;

    //
    // Return code from last function called
    //

    NTSTATUS        Status;

    //
    // Configuration data :
    //

    SB_CONFIG_DATA  ConfigData;

    //
    // Where we keep all general driver information
    // We avoid using static data because :
    //     1. Accesses are slower with 32-bit offsets
    //     2. We support more than one card instance
    //

    PGLOBAL_DEVICE_INFO pGDI;

    //
    // The number of devices we actually create
    //

    int         NumberOfDevicesCreated;

    //
    //  The context is the global device info pointer from the previous
    //  instance
    //

    CardInstance = Context;


   /********************************************************************
    *
    * Allocate our global info
    *
    ********************************************************************/

    pGDI =
        (PGLOBAL_DEVICE_INFO)ExAllocatePool(
                                  NonPagedPool,
                                  sizeof(GLOBAL_DEVICE_INFO));

    if (pGDI == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    dprintf4((" DriverEntry():  GlobalInfo    : %08lXH", pGDI));

    RtlZeroMemory(pGDI, sizeof(GLOBAL_DEVICE_INFO));
    pGDI->Key              = GDI_KEY;
    pGDI->Hw.Key           = HARDWARE_KEY;
    pGDI->RegistryPathName = RegistryPathName;

    pGDI->Usage            = 0xFF;                    // Free
    pGDI->DriverObject     = CardInstance->pDriverObject;

    //
    // Mutual exclusion :
    //
    //    Everything is synchronized on the DeviceMutex (except for
    //    some stuff inside the wave device) except
    //
    //    Midi external output which takes too long and so is synchronized
    //    separately but grabs the DeviceMutex every time it actually
    //    writes anything and
    //
    //    Synth output where the hardware is separate but callbacks to the
    //    mixer must grab the DeviceMutex.
    //

    KeInitializeMutex(&pGDI->DeviceMutex,
                       2                     // High level
                       );

    KeInitializeMutex(&pGDI->MidiMutex,
                       1                     // Low level
                       );

    KeInitializeMutex(&pGDI->Hw.DSPMutex,
                       3                     // Highest level
                       );

   /********************************************************************
    *
    *  Add ourselves to the ring of cards
    *
    ********************************************************************/

    if (CardInstance->PrevGDI == NULL) {
        pGDI->Next = pGDI;
    } else {
        PGLOBAL_DEVICE_INFO pNext;
        pNext = CardInstance->PrevGDI->Next;
        CardInstance->PrevGDI->Next = pGDI;
        pGDI->Next = pNext;
    }
    CardInstance->PrevGDI = pGDI;


   /********************************************************************
    *
    *  See if we can find our bus.  We run on both ISA and EISA
    *  We ASSUME that if there's an ISA bus we're on that
    *
    ********************************************************************/

    Status = SoundGetBusNumber(Isa, &pGDI->BusNumber);

    if (!NT_SUCCESS(Status)) {
        //
        // Cound not find an ISA bus so try EISA
        //
        Status = SoundGetBusNumber(Eisa, &pGDI->BusNumber);

        if (!NT_SUCCESS(Status)) {
            Status = SoundGetBusNumber(MicroChannel, &pGDI->BusNumber);

            if (!NT_SUCCESS(Status)) {
                dprintf1(("driver does not work on non-Isa/Eisa/Mca"));
                return Status;
            }
            pGDI->BusType = MicroChannel;

        } else {
            pGDI->BusType = Eisa;
        }
    } else {
        pGDI->BusType = Isa;
    }

    //
    // Set configuration to default in case we don't get all the
    // values back from the registry.
    //
    // Also set default volume for all devices
    //

    ConfigData.Port            = SOUND_DEF_PORT;
    ConfigData.InterruptNumber = SOUND_DEF_INT;
    ConfigData.DmaChannel      = SOUND_DEF_DMACHANNEL;
    ConfigData.DmaChannel16    = SOUND_DEF_DMACHANNEL16;
    ConfigData.DmaBufferSize   = DEFAULT_DMA_BUFFERSIZE;
    ConfigData.MPU401Port      = SOUND_DEF_MPU401_PORT;
    ConfigData.LoadType        = SOUND_LOADTYPE_NORMAL;
    ConfigData.MixerSettingsFound = FALSE;

    //
    // Get the system configuration information for this driver.
    //
    //
    //     Port, Interrupt, DMA channel, DMA 16-bit channel DMA buffer size
    //

    {
        RTL_QUERY_REGISTRY_TABLE    Table[2];

        RtlZeroMemory(Table, sizeof(Table));

        Table[0].QueryRoutine = SoundReadConfiguration;

        Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
                                         pGDI->RegistryPathName,
                                         Table,
                                         &ConfigData,
                                         NULL );

        if (!NT_SUCCESS(Status)) {
            dprintf1(("ERROR: DriverEntry(): RtlQueryRegistryValues() Failed with Status = %XH", Status));
            return Status;
        }           // End IF (!NT_SUCCESS(Status))
    }           // End Query Resistry Values

    //
    // Save additional Config data
    //
    pGDI->InterruptNumber = ConfigData.InterruptNumber;
    pGDI->DmaChannel      = ConfigData.DmaChannel;
    pGDI->DmaChannel16    = ConfigData.DmaChannel16;

    //
    // Verify the DMA Buffer Size
    //
    if ( ConfigData.DmaBufferSize < MIN_DMA_BUFFERSIZE ) {
        ConfigData.DmaBufferSize = MIN_DMA_BUFFERSIZE;
        dprintf1((" DriverEntry(): Adjusting the DMA Buffer size, size in Registry was too small"));
    }

    //
    // print out some info about the configuration
    //

    dprintf2((" DriverEntry():  Base I/O Port     = %XH", ConfigData.Port));
    dprintf2((" DriverEntry():  Interrupt         = %u",  ConfigData.InterruptNumber));
    dprintf2((" DriverEntry():  DMA Channel       = %u",  ConfigData.DmaChannel));
    dprintf2((" DriverEntry():  DMA Channel (16 bit) = %u",  ConfigData.DmaChannel16));
    dprintf2((" DriverEntry():  DMA Buffer Size   = %XH", ConfigData.DmaBufferSize));
    dprintf2((" DriverEntry():  MPU 401 port      = %XH", ConfigData.MPU401Port));

    /*
    **  Create our wave devices to ease reporting problems
    */

    Status = SBCreateDevice(pGDI, WaveInDevice);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    Status = SBCreateDevice(pGDI, WaveOutDevice);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    /*
    **  Say we want to be called at shutdown time
    */

    Status = IoRegisterShutdownNotification(pGDI->DeviceObject[WaveInDevice]);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    pGDI->ShutdownRegistered = TRUE;


    /*
    **  Check the configuration and acquire the resources
    */

    Status = SoundInitHardwareConfig(pGDI, &ConfigData);

    if (!NT_SUCCESS(Status)) {
        dprintf1(("ERROR: DriverEntry(): SoundInitHardwareConfig() Failed with Status = %XH",
                                 Status));
        return Status;
    }

    /*
    **  Initialize generic device environments - first get the
    **  hardware routines in place.
    **  We do this here after we've found out what hardware we've got
    */

    HwInitialize(pGDI);

    SoundInitMidiIn(&pGDI->MidiInfo,
                    &pGDI->Hw);


    /*
    **  Register most of our resources.  Some may be registered on
    **  the wave output device :
    **     16-bit dma channel
    **
    **  We wipe out the registration of the MPU401 port when we do this
    **  but this is OK.
    */

    {
        ULONG PortToReport;
        PortToReport = ConfigData.Port + MIX_ADDR_PORT;

        Status = SoundReportResourceUsage(
                     pGDI->DeviceObject[WaveInDevice],  // As good as any device to own
                                                   // it
                     pGDI->BusType,
                     pGDI->BusNumber,
                     &ConfigData.InterruptNumber,
                     INTERRUPT_MODE,
                     (BOOLEAN)(SB16(&pGDI->Hw) ? TRUE : FALSE),  // Sharable for SB16
                     &ConfigData.DmaChannel,
                     &PortToReport,
                     NUMBER_OF_SOUND_PORTS - MIX_ADDR_PORT);
    }

    if (!NT_SUCCESS(Status)) {
        dprintf1(("Error - failed to claim resources - code %8X", Status));
        pGDI->LoadStatus = SOUND_CONFIG_ERROR;
        return Status;
    }
    /*
    **  Now we know what device we've got we can create the appropriate
    **  devices
    */

    /*
    **  Thuderboard has no external midi and we're going to
    **  drive the SB16 in MPU401 mode if we can
    */

    if (!pGDI->Hw.ThunderBoard) {
        //
        //  Don't create the MPU401 device if it is disabled
        //
        if (!SB16(&pGDI->Hw) ||
            (ULONG)-1 != ConfigData.MPU401Port)
        {
            Status = SBCreateDevice(pGDI, MidiOutDevice);
            if (!NT_SUCCESS(Status)) {
                return Status;
            }
            Status = SBCreateDevice(pGDI, MidiInDevice);
            if (!NT_SUCCESS(Status)) {
                return Status;
            }
        }
    }

    /*
    **  Create volume control stuff for those devices which have it
    */

    if (SBPRO(&pGDI->Hw) || SB16(&pGDI->Hw)
#ifdef SB_CD
        ||
        pGDI->Hw.SBCDBase != NULL
#endif // SB_CD
        ) {
        Status = SBCreateDevice(pGDI, LineInDevice);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }
        Status = SBCreateDevice(pGDI, CDInternal);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }
        Status = SBCreateDevice(pGDI, MixerDevice);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }
    } else {
        /*  Volume setting not supported for our wave device */
        ((PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveOutDevice]->DeviceExtension)->CreationFlags |=
            SOUND_CREATION_NO_VOLUME;
    }

    /*
    ** Init the WaveInfo structure
    */

    SoundInitializeWaveInfo(&pGDI->WaveInfo,
                            (UCHAR)(SB1(&pGDI->Hw) ?
                                        SoundReprogramOnInterruptDMA :
                                        SoundAutoInitDMA),
                            SoundQueryFormat,
                            &pGDI->Hw);

    if (ConfigData.SynthType == SOUND_SYNTH_TYPE_NONE) {
        /*
        **  This will happen if the user selected a basic config without
        **  a synthesizer.
        */
        dprintf2(("No synth!"));
    } else {
        Status = SynthInit(CardInstance->pDriverObject,
                           pGDI->RegistryPathName,
                           &pGDI->Synth,
                           SB16(&pGDI->Hw) ||
                           SBPRO(&pGDI->Hw) && INPORT(&pGDI->Hw, 0) == 0 ?
                               ConfigData.Port : SYNTH_PORT,
                           FALSE,                         // Interrupt not enabled
                           pGDI->BusType,
                           pGDI->BusNumber,
                           NULL,
                           SOUND_MIXER_INVALID_CONTROL_ID,// Set volume later
                           TRUE,                          // Allow multiple
                           SoundMidiOutGetSynthCaps
                           );
        
        if (!NT_SUCCESS(Status)) {
        
            /*
            **  OK - we can get along without a synth
            */
        
            dprintf2(("No synth!"));
        } else {
            if (!pGDI->Synth.IsOpl3) {
                dprintf2(("Synth is Adlib"));
            } else {
        
                /*
                **  Bad aliasing in early sound blasters means we can
                **  guess wrong.
                */
        
                if (!(SB16(&pGDI->Hw) || SBPRO(&pGDI->Hw) && INPORT(&pGDI->Hw, 0) == 0)) {
                    pGDI->Synth.IsOpl3 = FALSE;
                }
                dprintf2(("Synth is Opl3"));
            }
        }
    }

    /*
    **  Set the mixer up.
    **
    **  Note that the mixer info depends on what hardware is present
    **  so this must be called after we have checked out the hardware.
    */

    if (pGDI->DeviceObject[MixerDevice]) {
        Status = SoundMixerInit(pGDI->DeviceObject[MixerDevice]->DeviceExtension,
                                &ConfigData.MixerSettings,
                                ConfigData.MixerSettingsFound);

        if (!NT_SUCCESS(Status)) {
            return Status;
        }
    }

    /*
    ** Save new settings
    */

    Status = SoundSaveConfig(pGDI->RegistryPathName,
                             ConfigData.Port,
                             ConfigData.DmaChannel,
                             ConfigData.DmaChannel16,
                             ConfigData.InterruptNumber,
                             ConfigData.MPU401Port,
                             (BOOLEAN)(pGDI->Synth.DeviceObject != NULL),
                             pGDI->Synth.IsOpl3,
                             pGDI->WaveInfo.DMABuf.BufferSize);

    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    /*
    **  Finally test the PRO interrupt
    */

    if (SBPRO(&pGDI->Hw)) {
        BOOLEAN Ok;

        SoundEnter(pGDI->DeviceObject[WaveOutDevice]->DeviceExtension,
                   TRUE);
        Ok = 0 == SoundTestWaveDevice(pGDI->DeviceObject[WaveOutDevice]);
        SoundEnter(pGDI->DeviceObject[WaveOutDevice]->DeviceExtension,
                   FALSE);
        if (!Ok) {
            pGDI->LoadStatus = SOUND_CONFIG_BADDMA;
            return STATUS_DEVICE_CONFIGURATION_ERROR;
        }
    }

    /*
    ** Exit OK Message
    */

    pGDI->LoadStatus = SOUND_CONFIG_OK;

    return STATUS_SUCCESS;

}
Beispiel #8
0
BOOLEAN
mpuRead(
    IN    PSOUND_HARDWARE pHw,
    OUT   PUCHAR pValue
)
/*++

Routine Description:

    Read the MPU data port
    Time out occurs after about 1ms

Arguments:

    pHw - Pointer to the device extension data.
    pValue - Pointer to the UCHAR to receive the result

Return Value:

    Value read

--*/
{
    USHORT uCount;
    BOOLEAN Status = FALSE;

    ASSERT(pHw->Key == HARDWARE_KEY);

    uCount = 100;

    while (uCount--) {
        int InnerCount;

        //
        // Protect all reads and writes with a spin lock
        //

        HwEnter(pHw);

        //
        // Inner count loop protects against dynamic deadlock with
        // midi.
        //

        for (InnerCount = 0; InnerCount < 10; InnerCount++) {
            if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) {  // do we have data waiting (bit 7 clear)? - drude
                *pValue = INPORT(pHw, MPU_DATA_PORT);
                uCount = 0;
                Status = TRUE;  // flag as data read
                break;
            }
            KeStallExecutionProcessor(1);
        }

        HwLeave(pHw);
    }
    
    // did we time out
    if(Status)
      return TRUE;  // data was read
    else
      return FALSE; // timed out
}
Beispiel #9
0
BOOLEAN
mpuReset(
    PSOUND_HARDWARE pHw
)
/*++

Routine Description:

    Reset the MPU to UART mode.

Arguments:

    pHw - pointer to the device extension data

Return Value:

    TRUE if we succeeded, FALSE if we failed.

--*/
{

    //
    // try for a reset - note that midi output may be running at this
    // point so we need the spin lock while we're trying to reset
    //

    BYTE    Ack = 0;
    int     i;


    HwEnter(pHw);

    // dump the current hardware midi input buffer
    // (We might have data availible if the midi devices
    //  connected have sent anything at all.)
    mpuDumpBufferNoLock(pHw);

    // reset the card
    OUTPORT(pHw, MPU_COMMAND_PORT, 0xFF);  // set to smart mode first

    // wait for the acknowledgement - drude
    // NOTE: When the Ack arrives, it will trigger an interrupt.  
    //       Normally the DPC routine would read in the ack byte and we
    //       would never see it, however since we have the hardware locked (HwEnter),
    //       we can read the port before the DPC can and thus we receive the
    //       Ack.
    for(i = 10000; i > 0; i--)  // some times it takes a really long time
    {
      if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) {  // do we have data waiting (bit 7 clear)?
          Ack = INPORT(pHw, MPU_DATA_PORT);  // read the ack byte
          break;
      }
      KeStallExecutionProcessor(25);
    }

    // NOTE: We cannot check the ACK byte because if the card was already in
    // UART mode it will not send an ACK but it will reset.

    // reset the card again
    OUTPORT(pHw, MPU_COMMAND_PORT, 0x3F);  // set to UART mode

    // wait for the acknowledgement
    Ack = 0;
    for(i = 10000; i > 0; i--)
    {
      if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) {  // do we have data waiting (bit 7 clear)?
          Ack = INPORT(pHw, MPU_DATA_PORT);  // read the ack byte
          break;
      }
      KeStallExecutionProcessor(25);
    }

    HwLeave(pHw);
    

    // did we succeed? - drude
    // (if we did not receive the second ACK, 
    //  something is wrong with the hardware.)
    if(Ack != 0xFE)
    {
      dprintf1(("mpuReset:reset hardware failed: %x", (ULONG)Ack));
      return FALSE;
    }
    else
    {
      dprintf1(("mpuReset:reset hardware OK"));
      return TRUE;
    }
}
Beispiel #10
0
NTSTATUS
SoundPortValid(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PULONG Port
)
{
    NTSTATUS Status;

    //
    // Check we're going to be allowed to use this port or whether
    // some other device thinks it owns this hardware
    //

    Status = SoundReportResourceUsage(
		 pGDI->DeviceObject[WaveInDevice],  // As good as any device to own
					       // it
		 pGDI->BusType,
		 pGDI->BusNumber,
		 NULL,
		 0,
		 FALSE,
		 NULL,
		 Port,
		 NUMBER_OF_SOUND_PORTS);

    if (!NT_SUCCESS(Status)) {
	return Status;
    }

    //
    // Find where our device is mapped
    //

    pGDI->Hw.PortBase = SoundMapPortAddress(
			       pGDI->BusType,
			       pGDI->BusNumber,
			       *Port,
			       NUMBER_OF_SOUND_PORTS,
			       &pGDI->MemType);

    //
    // Finally we can check and see if the hardware is happy
    //

    if (HwIsIoValid(&pGDI->Hw)) {
	//
	// Check if it's compaq Business Audio
	//

#if !(_ON_PLANNAR_)

	if ((INPORT(&pGDI->Hw, BOARD_ID) & 0x3F) != FH_PAL_PRODUCTREV_RQD) {


	    SoundCheckCompaqBA(pGDI, *Port);
	}
#endif
	return STATUS_SUCCESS;
    }

    //
    // Free any resources.  (note we don't have to do
    // IoReportResourceUsage again because each one overwrites the
    // previous).
    //

    if (pGDI->MemType == 0) {
	MmUnmapIoSpace(pGDI->Hw.PortBase, NUMBER_OF_SOUND_PORTS);
    }
    pGDI->Hw.PortBase = NULL;

    return STATUS_DEVICE_CONFIGURATION_ERROR;
}
Beispiel #11
0
NTSTATUS
SoundCheckCompaqBA(PGLOBAL_DEVICE_INFO pGDI, ULONG SoundPort)
{
    NTSTATUS Status;
    ULONG Port;
    UCHAR CompaqPCR;

    //
    // Only 530 and 604 supported
    //

    if (SoundPort != 0x530 && SoundPort != 0x604) {
	return STATUS_DEVICE_CONFIGURATION_ERROR;
    }

    Port = 0xC44;

    //
    // Go and search at C44 - attach it to the wave in device so it will be
    // overwritten later since we don't want to keep it
    //
    Status = SoundReportResourceUsage(
		 pGDI->DeviceObject[WaveInDevice],
		 pGDI->BusType,
		 pGDI->BusNumber,
		 NULL,
		 0,
		 FALSE,
		 NULL,
		 &Port,
		 1);

    if (!NT_SUCCESS(Status)) {
	return Status;
    }

    //
    // Find where our device is mapped and map 4 bytes to cover
    // C44 and C47
    //

    pGDI->Hw.CompaqBA = SoundMapPortAddress(
			       pGDI->BusType,
			       pGDI->BusNumber,
			       Port,
			       4,
			       &pGDI->MemType);

    //
    // Read the peripheral Configuration Register (PCR)
    //

    CompaqPCR = READ_PORT_UCHAR(pGDI->Hw.CompaqBA);

    //
    // See if the PCR agress with where we think the hardware is
    //
    //	0x10 bit says sound enabled
    //	0x20 bit says it's at 604 (rather than 530)
    //

    if (CompaqPCR != 0xFF &&
	((CompaqPCR & 0x30) == 0x10 && SoundPort == 0x530 ||
	 (CompaqPCR & 0x30) == 0x30 && SoundPort == 0x604)) {

	 //
	 // Looks like the base address is really at C44.  In
	 // this case we re-report so that we don't prevent others
	 // looking at the PCR since from now on we're only interested
	 // in 0xC47
	 //

	 Port += BOARD_ID;

	 Status = SoundReportResourceUsage(
		      pGDI->DeviceObject[WaveOutDevice],
		      pGDI->BusType,
		      pGDI->BusNumber,
		      NULL,
		      0,
		      FALSE,
		      NULL,
		      &Port,
		      1);

    } else {
	//
	// Unmap  - we don't need to unreport because our final declaration
	// of what we use will overwrite our reporting of C44
	//

	if (pGDI->MemType == 0) {
	    MmUnmapIoSpace(pGDI->Hw.CompaqBA, 4);
	}
	pGDI->Hw.CompaqBA = NULL;


	//
	// It might be the old Compaq Business Audio 1
	// The Red I (early Prolinea/I boxes) did not use the C44
	// port but instaed used the actual ports, so lets try again
	//

	CompaqPCR = INPORT(&pGDI->Hw, BOARD_CONFIG);

	if (CompaqPCR == 0xFF) {
	    //
	    // Must be one of the really old machines
	    // We'll test the interrupt and DMA later
	    //

	    pGDI->Hw.CompaqBA = pGDI->Hw.PortBase;
	    pGDI->Hw.NoPCR = TRUE;

	    return STATUS_SUCCESS;
	}

	if ((CompaqPCR & 0x30) == 0x10 && SoundPort == 0x530 ||
	    (CompaqPCR & 0x30) == 0x30 && SoundPort == 0x604) {

	     pGDI->Hw.CompaqBA = pGDI->Hw.PortBase;

	     Status = STATUS_SUCCESS;
	} else {
	     Status = STATUS_DEVICE_CONFIGURATION_ERROR;
	}
    }

    return Status;
}