diff --git a/src/add-ons/kernel/generic/mpu401/Jamfile b/src/add-ons/kernel/generic/mpu401/Jamfile index 024d29963c..82dbe8ccbc 100644 --- a/src/add-ons/kernel/generic/mpu401/Jamfile +++ b/src/add-ons/kernel/generic/mpu401/Jamfile @@ -2,5 +2,6 @@ SubDir HAIKU_TOP src add-ons kernel generic mpu401 ; KernelAddon mpu401 : kernel generic : mpu401.c + debug.c ; diff --git a/src/add-ons/kernel/generic/mpu401/debug.c b/src/add-ons/kernel/generic/mpu401/debug.c new file mode 100644 index 0000000000..2807f8d19b --- /dev/null +++ b/src/add-ons/kernel/generic/mpu401/debug.c @@ -0,0 +1,87 @@ +/* + * BeOS Driver for Intel ICH AC'97 Link interface + * + * Copyright (c) 2002, Marcus Overhagen + * + * All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include +#include +#include +#include +#include "debug.h" + +#define DRIVER_NAME "mpu401" +#define VERSION "0.2" + +void debug_printf(const char *text,...) +{ + char buf[1024]; + va_list ap; + + va_start(ap,text); + vsprintf(buf,text,ap); + va_end(ap); + + dprintf(DRIVER_NAME ": %s",buf); +} + +#if DEBUG > 0 + +static const char * logfile="/boot/home/mpu401.log"; +static sem_id loglock; + +void log_create(void) +{ + int fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); + const char *text = DRIVER_NAME ", " VERSION "\n"; + loglock = create_sem(1,"logfile sem"); + write(fd,text,strlen(text)); + close(fd); +} + +void log_printf(const char *text,...) +{ + int fd; + char buf[1024]; + va_list ap; + + va_start(ap,text); + vsprintf(buf,text,ap); + va_end(ap); + + dprintf(DRIVER_NAME ": %s",buf); + + acquire_sem(loglock); + fd = open(logfile, O_WRONLY | O_APPEND); + write(fd,buf,strlen(buf)); + close(fd); + release_sem(loglock); + + #if DEBUG > 1 + snooze(150000); + #endif +} + +#endif diff --git a/src/add-ons/kernel/generic/mpu401/debug.h b/src/add-ons/kernel/generic/mpu401/debug.h new file mode 100644 index 0000000000..87ffd60141 --- /dev/null +++ b/src/add-ons/kernel/generic/mpu401/debug.h @@ -0,0 +1,69 @@ +/* + * BeOS Driver for Intel ICH AC'97 Link interface + * + * Copyright (c) 2002, Marcus Overhagen + * + * All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +/* + * PRINT() executes dprintf if DEBUG = 0 (disabled), or expands to LOG() when DEBUG > 0 + * TRACE() executes dprintf if DEBUG > 0 + * LOG() executes dprintf and writes to the logfile if DEBUG > 0 + */ + +/* DEBUG == 0, no debugging, PRINT writes to syslog + * DEBUG == 1, TRACE & LOG, PRINT + * DEBUG == 2, TRACE & LOG, PRINT with snooze() + */ +#ifndef DEBUG + #define DEBUG 1 +#endif + +#undef PRINT +#undef TRACE +#undef ASSERT + +void debug_printf(const char *text,...); + +#if DEBUG > 0 + #define PRINT(a) log_printf a + #define TRACE(a) debug_printf a + #define LOG(a) log_printf a + #define LOG_CREATE() log_create() + #define DEBUG_ONLY(a) a + #define ASSERT(a) if (a) {} else LOG(("ASSERT failed! file = %s, line = %d\n",__FILE__,__LINE__)) + void log_create(void); + void log_printf(const char *text,...); +#else + #define PRINT(a) debug_printf a + #define TRACE(a) ((void)(0)) + #define ASSERT(a) ((void)(0)) + #define LOG(a) ((void)(0)) + #define LOG_CREATE() + #define DEBUG_ONLY(a) +#endif + +#endif diff --git a/src/add-ons/kernel/generic/mpu401/mpu401.c b/src/add-ons/kernel/generic/mpu401/mpu401.c index 653b5673b7..91c5138ffc 100644 --- a/src/add-ons/kernel/generic/mpu401/mpu401.c +++ b/src/add-ons/kernel/generic/mpu401/mpu401.c @@ -1,26 +1,25 @@ -/* - * OpenBeOS - * A module driver for the generic mpu401 midi interface - * - * Copyright (c) 2003 Greg Crain - * All rights reserved. - * This software is released under the MIT/OpenBeOS license. - * - * mpu401.c - */ +/* +* Copyright 2003-2006, Haiku. +* Distributed under the terms of the MIT License. +* +* A module driver for the generic mpu401 midi interface. +* +* Author: +* Greg Crain (gsc70@comcast.net) +* +* mpu401.c +*/ -#include -#include #include +#include +#include #include #include #include +#include +#include "debug.h" #include "mpu401_priv.h" - -// UART data port = addr -// UART cmd port = addr +1 - /* ---------- midi_create_device - ----- */ @@ -31,32 +30,27 @@ static status_t create_device(int port, void ** out_storage, uint32 workarounds, void (*interrupt_op)(int32 op, void * card), void * card) { - mpu401device mpu_device; - mpu401device *mpuptr; + mpu401device mpu_device; + mpu401device *mpuptr; - /* fill the structure with specific info from caller */ - mpu_device.dataport = port; - mpu_device.cmdport = port+1; - mpu_device.workarounds = workarounds; - mpu_device.V2 = FALSE; - mpu_device.count = 1; - mpu_device.interrupt_op = interrupt_op; + /* fill the structure with specific info from caller */ + mpu_device.addrport = port; + mpu_device.workarounds = workarounds; + mpu_device.V2 = FALSE; + mpu_device.count = 1; + mpu_device.interrupt_op = interrupt_op; + mpu_device.card = card; -#if MPUDEBUG - dprintf("mpu401:create_device - count = %ld ,",mpu_device.count); - dprintf("dataport 0x%x ,",mpu_device.dataport); - dprintf("workarounds: %d\n",mpu_device.workarounds); - dprintf("**outstorage: %p\n",out_storage); -#endif + LOG(("create_device count= %ld, addrport 0x%x, workarounds: %d",mpu_device.count, mpu_device.addrport, mpu_device.workarounds)); // basically, each call to create device allocates memory for //a structure with the specific device info. The pointer to this is // returned back to calling driver - mpuptr = (mpu401device*)malloc ( sizeof(mpu401device)); - memcpy ( mpuptr, &mpu_device, sizeof(mpu_device)); + mpuptr = (mpu401device*)malloc (sizeof(mpu401device)); + memcpy(mpuptr, &mpu_device, sizeof(mpu_device)); *out_storage = (void *)mpuptr; - return (B_OK); + return B_OK; } /*-----------------------------*/ /* Version 2 of mpu401 module */ @@ -65,15 +59,11 @@ create_device(int port, void ** out_storage, uint32 workarounds, void (*interrup static status_t create_device_v2(int port, void ** out_storage, uint32 workarounds, void (*interrupt_op)(int32 op, void * card), void * card) { - mpu401device *mpuptr; - mpu401device mpu_device; + mpu401device *mpuptr; + mpu401device mpu_device; + + LOG(("v2: create_device, **out_storage %p ,workarounds %ld ,void *card %p\n",out_storage, workarounds, card)); -#if MPUDEBUG - dprintf("mpu401_v2: create_device\n"); - dprintf("mpu401_v2: **out_storage %p ,",out_storage); - dprintf("workarounds %ld ,",workarounds); - dprintf("void *card %p\n",card); -#endif // not sure exactly how v2 of the module works. I think that two ports are // created. One for midi in data, and another for midi out data. // Instead of transfering data using a buffer and pointer, the midi @@ -87,18 +77,18 @@ create_device_v2(int port, void ** out_storage, uint32 workarounds, void (*inter // those calls, it needs to be known whether the mididata is to be read/written // to a buffer, or to the port. - mpu_device.dataport = port; - mpu_device.cmdport = port+1; + mpu_device.addrport = port; mpu_device.workarounds = workarounds; mpu_device.V2 = TRUE; mpu_device.count =1; + mpu_device.card = card; - mpuptr = (mpu401device*)malloc ( sizeof(mpu401device)); - memcpy ( mpuptr, &mpu_device, sizeof(mpu_device)); + mpuptr = (mpu401device*)malloc(sizeof(mpu401device)); + memcpy(mpuptr, &mpu_device, sizeof(mpu_device)); *out_storage = (void *)mpuptr; - return (B_OK); + return B_OK; } @@ -108,21 +98,15 @@ create_device_v2(int port, void ** out_storage, uint32 workarounds, void (*inter static status_t delete_device(void * storage) { - mpu401device * mpu_device = (mpu401device *)storage; + mpu401device * mpu_device = (mpu401device *)storage; -#if MPUDEBUG - dprintf("mpu_device->dataport = 0x%x\n",mpu_device->dataport); - dprintf("mpu_device->count = %ld\n",mpu_device->count); -#endif -// if (mpu_device->count <=0) -// return (B_ERROR); -// else - - dprintf("mpu401: delete_device: *storage:%p\n",storage); - free(storage); // free the memory allocated in create_device + LOG(("device->addrport= 0x%x count= %ld\n",mpu_device->addrport, mpu_device->count)); + LOG(("delete_device: *storage:%p\n",storage)); + + free(storage); // free the memory allocated in create_device atomic_add(&mpu_device->count,-1); - return (B_OK); + return B_OK; } /* ---------- @@ -132,71 +116,69 @@ delete_device(void * storage) static status_t midi_open(void * storage, uint32 flags, void ** out_cookie) { - char semname[25]; - int ack_byte; + char semname[25]; + int ack_byte; mpu401device * mpu_device = (mpu401device *)storage; -#if MPUDEBUG - dprintf("mpu401: midi_open() flags: %ld,",flags); - dprintf(" * storage: %p,", storage); - dprintf(" **out_cookie: %p\n",out_cookie); - dprintf("mpu401:@open: mpu_device->dataport 0x%x\n",mpu_device->dataport); - dprintf("mpu401:@open: mpu_device->workarounds %d\n",mpu_device->workarounds); -#endif + LOG(("open() flags: %ld, * storage: %p, **out_cookie: %p\n",flags, storage,out_cookie)); + LOG(("open: device->addrport 0x%x ,workarounds 0x%x\n",mpu_device->addrport, mpu_device->workarounds)); - // the undocumented V2 module is not complete - // we will allow the device to be created since some drivers depend on it - // but will return an error if the actual midi device is opened: - if ( mpu_device->V2 == TRUE) - return (B_ERROR); + // the undocumented V2 module is not complete + // we will allow the device to be created since some drivers depend on it + // but will return an error if the actual midi device is opened: + if ( mpu_device->V2 == TRUE) + return B_ERROR; - switch (mpu_device->workarounds){ - case 0: - // don't know the current mpu state - dprintf("mpu401: reset MPU401\n"); - Write_MPU401(mpu_device->cmdport, MPU401_RESET); - snooze (30000); - ack_byte = Read_MPU401(mpu_device->dataport); - dprintf("mpu401: enable UART mode\n"); - Write_MPU401(mpu_device->cmdport, MPU401_UART); - snooze (30000); - ack_byte = Read_MPU401(mpu_device->dataport ); - dprintf("port cmd ack is 0x%x\n", ack_byte); + switch (mpu_device->workarounds){ + case 0x11020004: // This is still required for Creative Audigy, Audidy2 + case 0x11020005: + case 0: + // don't know the current mpu state + PRINT(("reset MPU401\n")); + Write_MPU401(mpu_device->addrport, UARTCMD, mpu_device->workarounds, MPU401_RESET); + snooze(30000); + Write_MPU401(mpu_device->addrport, UARTCMD, mpu_device->workarounds, MPU401_RESET); + snooze(30000); + ack_byte = Read_MPU401(mpu_device->addrport, UARTDATA, mpu_device->workarounds); + PRINT(("enable UART mode\n")); + Write_MPU401(mpu_device->addrport, UARTCMD, mpu_device->workarounds, MPU401_UART); + snooze(30000); + ack_byte = Read_MPU401(mpu_device->addrport, UARTDATA, mpu_device->workarounds ); + PRINT(("port cmd ack is 0x%x\n", ack_byte)); *out_cookie = mpu_device; - break; - case 1: - // only a guess here... don't have any knowledge of workaround values - dprintf("mpu401a: in UART mode\n"); - break; - default: - dprintf("mpu401: Unknown workaround value: %d\n",mpu_device->workarounds); - break; + break; + case 1: + // Some devices are always in UART mode + PRINT(("already in UART mode\n")); + break; + default: + PRINT(("Unknown workaround value: %d\n", mpu_device->workarounds)); + break; } //end switch // Create Read semaphore for midi-in data - sprintf(semname,"mpu401:%04x:read_sem",mpu_device->dataport ); - mpu_device->readsemaphore = create_sem(0,semname); + sprintf(semname, "mpu401:%04x:read_sem", mpu_device->addrport); + mpu_device->readsemaphore = create_sem(0, semname); // Create Write semaphore for midi-out data - sprintf(semname,"mpu401:%04x:write_sem",mpu_device->dataport ); - mpu_device->writesemaphore = create_sem(1,semname); + sprintf(semname,"mpu401:%04x:write_sem", mpu_device->addrport); + mpu_device->writesemaphore = create_sem(1, semname); + // clear midi-in buffer + mbuf_bytes=0; + mbuf_current=0; + mbuf_start=0; + //Enable midi interrupts - mpu_device->interrupt_op(B_MPU_401_ENABLE_CARD_INT, &mpu_device); - - // clear midi-in buffer - mbuf_bytes=0; - mbuf_current=0; - mbuf_start=0; - - if ((mpu_device->readsemaphore > B_OK)&&(mpu_device->writesemaphore > B_OK)) - { - atomic_add(&mpu_device->count, 1); - dprintf("mpu401: midi_open() done (count = %x)\n", open_count); - return (B_OK); - } - else - return (B_ERROR); + mpu_device->interrupt_op(B_MPU_401_ENABLE_CARD_INT, mpu_device->card ); + + if ((mpu_device->readsemaphore > B_OK) + && (mpu_device->writesemaphore > B_OK)) { + atomic_add(&mpu_device->count, 1); + PRINT(("midi_open() done (count = %x)\n", open_count)); + return B_OK; + } + return B_ERROR; } /* ---------- @@ -207,35 +189,30 @@ midi_close(void * cookie) { mpu401device * mpu_device = (mpu401device *)cookie; -#if MPUDEBUG - dprintf("mpu401: close\n"); -#endif - if (mpu_device->count <= 0) - return(B_ERROR); + return B_ERROR; - //Disable soundcard midi interrupts - mpu_device->interrupt_op(B_MPU_401_DISABLE_CARD_INT, &mpu_device); + //Disable soundcard midi interrupts + mpu_device->interrupt_op(B_MPU_401_DISABLE_CARD_INT, mpu_device->card ); // Delete the semaphores delete_sem(mpu_device->readsemaphore); delete_sem(mpu_device->writesemaphore); atomic_add(&mpu_device->count, -1); - dprintf("mpu401: midi_close() done (count = %lu)\n", mpu_device->count); + PRINT(("midi_close() done (count = %lu)\n", mpu_device->count)); - return (B_OK); + return B_OK; } + /* ---------- midi_free - free up allocated memory ----- */ static status_t midi_free(void * cookie) { -#if MPUDEBUG - dprintf("mpu401: free\n"); -#endif - return (B_OK); + LOG(("midi_free()\n")); + return B_OK; } /* ---------- @@ -246,11 +223,9 @@ midi_control(void * cookie, uint32 op, void * data, size_t len) { //mpu401device *mpu_device = (mpu401device *)cookie; -/* I don't think this is ever called ...*/ -#if MPUDEBUG - dprintf("mpu401: control\n"); -#endif - return (B_OK); + /* I don't think this is ever called ...*/ + LOG(("midi_control()\n")); + return B_OK; } @@ -260,20 +235,15 @@ midi_control(void * cookie, uint32 op, void * data, size_t len) static status_t midi_read(void *cookie, off_t pos, void *buffer, size_t *num_bytes) { -/* The actual midi data is read from the device in the interrupt handler; + /* The actual midi data is read from the device in the interrupt handler; this reads and returns the data from a buffer */ -unsigned char *data; -unsigned int i; -size_t count; -cpu_status status; -status_t bestat; -mpu401device *mpu_device = (mpu401device *)cookie; - - -#if 0 - dprintf("mpu401: read\n"); -#endif + unsigned char *data; + unsigned int i; + size_t count; + cpu_status status; + status_t bestat; + mpu401device *mpu_device = (mpu401device *)cookie; data = (unsigned char*)buffer; count = *(num_bytes); @@ -281,36 +251,30 @@ mpu401device *mpu_device = (mpu401device *)cookie; i=0; *num_bytes=0; bestat = acquire_sem_etc ( mpu_device->readsemaphore, 1, B_CAN_INTERRUPT, 0); - if (bestat == B_INTERRUPTED) - { - #if MPUDEBUG - dprintf("mpu401: acquire_sem B_INTERRUPTED!\n"); - #endif - return (B_INTERRUPTED); - } - if (bestat != B_OK) - { - #if MPUDEBUG - dprintf("mpu401: acquire_sem not B_OK %d\n",bestat); - #endif - *num_bytes = 1; - return (B_INTERRUPTED); - } - if (bestat == B_OK) - { - status = lock(); - *(data+i) = mpubuffer[mbuf_start]; - i++; - mbuf_start++; // pointer to data in ringbuffer - if (mbuf_start >= (MBUF_ELEMENTS-1)) - mbuf_start = 0; //wraparound of ringbuffer - *num_bytes =1; // tell caller how many bytes are being returned in buffer - if (mbuf_bytes>0) mbuf_bytes--; // bytes read from buffer, so decrement buffer count - unlock(status); - //dprintf("mpu401: bytes in buffer: %d\n",mbuf_bytes); - } - - return (B_OK); + if (bestat == B_INTERRUPTED) { + //PRINT(("acquire_sem B_INTERRUPTED!\n")); + return B_INTERRUPTED; + } + if (bestat != B_OK) { + TRACE(("acquire_sem not B_OK %d\n",(int)bestat)); + *num_bytes = 1; + return B_INTERRUPTED; + } + if (bestat == B_OK) { + status = lock(); + *(data+i) = mpubuffer[mbuf_start]; + i++; + mbuf_start++; // pointer to data in ringbuffer + if (mbuf_start >= (MBUF_ELEMENTS-1)) + mbuf_start = 0; //wraparound of ringbuffer + *num_bytes =1; // tell caller how many bytes are being returned in buffer + if (mbuf_bytes>0) + mbuf_bytes--; // bytes read from buffer, so decrement buffer count + unlock(status); + //PRINT(("bytes in buffer: %d\n",mbuf_bytes)); + } + + return B_OK; } /* ---------- @@ -319,32 +283,28 @@ mpu401device *mpu_device = (mpu401device *)cookie; static status_t midi_write(void * cookie, off_t pos, const void * data, size_t * num_bytes) { - unsigned char *bufdata; - uint32 i; - size_t count; + unsigned char *bufdata; + uint32 i; + size_t count; mpu401device *mpu_device = (mpu401device *)cookie; bufdata = (unsigned char*)data; /* Pointer to midi data buffer */ count = *num_bytes; -#if 0 - dprintf("mpu401_w: write %d bytes\n",count); - dprintf("mpu401_w: mpu_device->dataport 0x%x\n",mpu_device->dataport); - dprintf("mpu401_w: workarounds %d\n",mpu_device->workarounds); -#endif + /* Only for deep debugging..will slow things down */ + //PRINT(("write %d bytes, addrport 0x%x, workarounds 0x%x\n",(int)count,mpu_device->addrport, mpu_device->workarounds)); - acquire_sem (mpu_device->writesemaphore); - for (i=0; icmdport) & MPU401_OK2WR)); - Write_MPU401 ( mpu_device->dataport, *(bufdata+i) ); - } + acquire_sem(mpu_device->writesemaphore); + for (i=0; iaddrport, UARTCMD, mpu_device->workarounds) & MPU401_OK2WR)); + Write_MPU401(mpu_device->addrport, UARTDATA, mpu_device->workarounds, *(bufdata+i)); + } *num_bytes = 0; - release_sem (mpu_device->writesemaphore); + release_sem(mpu_device->writesemaphore); - return (B_OK); + return B_OK; } /* ---------- interrupt_hook - handle interrupts for mpu401 data @@ -355,77 +315,120 @@ interrupt_hook(void * cookie) status_t bestat; mpu401device *mpu_device = (mpu401device *)cookie; -#if 0 - dprintf("mpu401: irq! port: 0x%x\n",mpu_device->dataport); -#endif -/* Input data is available when bit 7 of the Status port is zero. Conversely, when bit 7 is - is a one, no MIDI data is available. Reading from the data port will clear the interrupt signal */ + //PRINT(("irq! port: 0x%x\n",mpu_device->addrport)); /* Only for deep debugging..will slow things down */ + + /* Input data is available when bit 7 of the Status port is zero. Conversely, when bit 7 is + is a one, no MIDI data is available. Reading from the data port will often clear the + interrupt signal depending on the sound card. */ - if ( (Read_MPU401(mpu_device->cmdport) & MPU401_OK2RD) == 0 ) - { + if ((Read_MPU401(mpu_device->addrport, UARTCMD, mpu_device->workarounds) & MPU401_OK2RD) == 0) { /* Okay, midi data waiting to be read from device */ if (mbuf_current >= (MBUF_ELEMENTS-1)) - mbuf_current = 0; + mbuf_current = 0; - mpubuffer[mbuf_current] = Read_MPU401(mpu_device->dataport); /* store midi data byte into buffer */ - mbuf_current++; /* pointer to next blank byte */ - mbuf_bytes++; /* increment count of midi data bytes */ + mpubuffer[mbuf_current] = Read_MPU401(mpu_device->addrport, + UARTDATA, mpu_device->workarounds); /* store midi data byte into buffer */ + mbuf_current++; /* pointer to next blank byte */ + mbuf_bytes++; /* increment count of midi data bytes */ bestat = release_sem_etc(mpu_device->readsemaphore, 1, B_DO_NOT_RESCHEDULE); - //bestat = get_sem_count ( mpu_device->readsemaphore, &semcount); - //dprintf("irq:get_sem_count: %d\n",semcount); - return (TRUE); //B_INVOKE_SCHEDULER - } - else - { - /* No midi data from this interrupt */ - return(FALSE); //B_UNHANDLED_INTERRUPT - } + return TRUE; //B_INVOKE_SCHEDULER + } + /* No midi data from this interrupt */ + return FALSE; //B_UNHANDLED_INTERRUPT } /*-----------------------------------------------------------------*/ -uchar Read_MPU401( unsigned int addrport ){ - +uchar +Read_MPU401(unsigned int addrport, const char cmdtype, unsigned int workarounds) +{ uchar mpudatabyte; + cpu_status status; + unsigned int regptr; - mpudatabyte = gISA->read_io_8(addrport); -// dprintf ("mpu401: read 0x%x\n",mpudatabyte); - - return (mpudatabyte); + //PRINT(("read workaround 0x%x\n",workarounds)); /* Only for deep debugging..will slow things down */ + switch (workarounds) { + case 0x11020004: /* Creative Audigy Gameport */ + regptr = (((I_MPU1 + cmdtype) << 16) & PTR_ADDRESS_MASK); + status = lock(); + gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA or CMD */ + mpudatabyte = gPCI->read_io_32(addrport + D_DATA); + unlock(status); + break; + + case 0x11020005: /* Creative Audigy LiveDrive */ + regptr = (((I_MPU2 + cmdtype) << 16) & PTR_ADDRESS_MASK); + status = lock(); + gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA2 or CMD2 */ + mpudatabyte = gPCI->read_io_32(addrport + D_DATA); + unlock(status); + break; + + default: + mpudatabyte = gISA->read_io_8(addrport + cmdtype ); + break; + } + return mpudatabyte; } -status_t Write_MPU401( int addrport, uchar mpudatabyte ){ -// dprintf("mpu401: write 0x%x",mpudatabyte); -// dprintf(" at addr: 0x%x\n",addrport); - gISA->write_io_8(addrport, mpudatabyte); +status_t +Write_MPU401(unsigned int addrport, const char cmdtype, unsigned int workarounds, uchar mpudatabyte ) +{ + cpu_status status; + unsigned int regptr; + + /* Only for deep debugging..will slow things down */ + //PRINT(("write workaround 0x%x at addr: 0x%x\n",workarounds,addrport)); + switch (workarounds) { + case 0x11020004: /* Creative Audigy Gameport */ + regptr = (((I_MPU1 + cmdtype ) << 16) & PTR_ADDRESS_MASK); + status = lock(); + gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA or CMD */ + gPCI->write_io_32(addrport + D_DATA, mpudatabyte ); + unlock(status); + break; - return (B_OK); + case 0x11020005: /* Creative Audigy LiveDrive */ + regptr = (((I_MPU2 + cmdtype ) << 16) & PTR_ADDRESS_MASK); + status = lock(); + gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA2 or CMD2 */ + gPCI->write_io_32(addrport + D_DATA, mpudatabyte ); + unlock(status); + break; + + default: + gISA->write_io_8(addrport + cmdtype, mpudatabyte); + break; + } + return B_OK; } + + /*-----------------------------------------------------------------*/ static status_t std_ops(int32 op, ...) { -#if MPUDEBUG - bool former; - former = set_dprintf_enabled ( true ); - dprintf("mpu401:std_ops 0x%lx\n", op); -#endif - switch(op) { case B_MODULE_INIT: - dprintf("mpu401: B_MODULE_INIT\n"); + + LOG_CREATE(); + PRINT(("B_MODULE_INIT\n")); + if (get_module(B_ISA_MODULE_NAME, (module_info **)&gISA) < B_OK) - return (B_ERROR); + return B_ERROR; + if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI) < B_OK) + return B_ERROR; return B_OK; case B_MODULE_UNINIT: - put_module (B_ISA_MODULE_NAME); - dprintf("mpu401: B_MODULE_UNINIT\n"); + put_module(B_ISA_MODULE_NAME); + put_module(B_PCI_MODULE_NAME); + PRINT(("B_MODULE_UNINIT\n")); return B_OK; default: @@ -450,6 +453,7 @@ static generic_mpu401_module mpu401_module = midi_write, interrupt_hook }; + // Module v2 seems to be undocumented static generic_mpu401_module mpu401_module2 = { @@ -477,16 +481,18 @@ _EXPORT generic_mpu401_module *modules[] = }; spinlock locked = 0; -cpu_status lock(void) +cpu_status +lock(void) { cpu_status status = disable_interrupts(); - acquire_spinlock (&locked); + acquire_spinlock(&locked); return status; } -void unlock( cpu_status status) +void +unlock(cpu_status status) { release_spinlock(&locked); - restore_interrupts (status); + restore_interrupts(status); } diff --git a/src/add-ons/kernel/generic/mpu401/mpu401_priv.h b/src/add-ons/kernel/generic/mpu401/mpu401_priv.h index b0f1606759..a687bfb6cd 100644 --- a/src/add-ons/kernel/generic/mpu401/mpu401_priv.h +++ b/src/add-ons/kernel/generic/mpu401/mpu401_priv.h @@ -1,53 +1,92 @@ -/* - * OpenBeOS - * A module driver for the generic mpu401 midi interface - * - * Copyright (c) 2003 Greg Crain - * All rights reserved. - * This software is released under the MIT/OpenBeOS license. - * - * mpu401_priv.h - */ +/* +* Copyright 2003-2006, Haiku. +* Distributed under the terms of the MIT License. +* +* A module driver for the generic mpu401 midi interface. +* +* Author: +* Greg Crain (gsc70@comcast.net) +* +* mpu401_priv.h +*/ -#ifndef mpu401_H -#define mpu401_H +#ifndef mpu401_priv_H +#define mpu401_priv_H #include +#include -//Private header info - - typedef struct _mpu401device -{ - unsigned int dataport; - unsigned int cmdport; - unsigned int workarounds; - int32 count; - bool V2; - sem_id readsemaphore; - sem_id writesemaphore; - void (*interrupt_op)(int32 op, void * card); -} mpu401device; +/*--------------------------------*/ +/* UART Definitions */ #define MPU401_RESET 0xff #define MPU401_UART 0x3f #define MPU401_CMDOK 0xfe #define MPU401_OK2WR 0x40 #define MPU401_OK2RD 0x80 +// Typically, +// UART data port = addr +// UART cmd port = addr +1 +#define UARTDATA 0 +#define UARTCMD 1 + +#define MBUF_ELEMENTS 1000 //Input buffer size -#define MPUDEBUG 1 -#define MBUF_ELEMENTS 1000 /*--------------------------------*/ -unsigned char Read_MPU401( unsigned int ); -status_t Write_MPU401( int, unsigned char ); +/* Private definitions */ + +typedef struct _mpu401device { + unsigned int addrport; + unsigned int workarounds; + int32 count; + bool V2; + sem_id readsemaphore; + sem_id writesemaphore; + void (*interrupt_op)(int32 op, void * card); + void *card; +} mpu401device; + +int mbuf_current; +int mbuf_start; +int mbuf_bytes; +unsigned char mpubuffer[MBUF_ELEMENTS]; +static int open_count; +static isa_module_info *gISA; +static pci_module_info *gPCI; + + +/*--------------------------------*/ +/* Function prototypes */ + +unsigned char Read_MPU401(unsigned int, const char, unsigned int); +status_t Write_MPU401(unsigned int, const char, unsigned int, uchar); + cpu_status lock(void); void unlock (cpu_status); -/*--------------------------------*/ -short open_count=0; -int mbuf_current=0; -int mbuf_start=0; -int mbuf_bytes=0; -unsigned char mpubuffer[MBUF_ELEMENTS]; -static isa_module_info *gISA; -#endif // mpu401.h +/********************/ +/* Workarounds */ +/********************/ +// This is a list of workarounds in order to +// get a specific manufacturer, card vendor, or UART type +// to work nicely with the generic module. +// The defined workaround value must match the value that +// is used in the driver 'create_device' call. + + +/****************************/ +/* Creative Audigy, Audigy2 */ +/****************************/ +/* 0x11020004 Gameport Midi connector */ +/* 0x11020005 LiveDrive Expansion connector */ +/* IN the create_device hook, use the PCI base*/ +/* address, instead of midi address port */ +#define PTR_ADDRESS_MASK 0x0fff0000 +#define D_DATA 0x04 +#define D_PTR 0x00 +#define I_MPU1 0x70 +#define I_MPU2 0x72 + + +#endif // mpu401_priv_H