From 6ffb178a0021221fb66ca3af5e5180658f9235f8 Mon Sep 17 00:00:00 2001 From: Jerome Leveque Date: Fri, 27 Jan 2012 20:09:35 +0000 Subject: [PATCH] Generic MPU401 driver: Add Ice1712 card, Fix line size > 80 --- src/add-ons/kernel/generic/mpu401/mpu401.c | 325 ++++++++++++--------- 1 file changed, 191 insertions(+), 134 deletions(-) diff --git a/src/add-ons/kernel/generic/mpu401/mpu401.c b/src/add-ons/kernel/generic/mpu401/mpu401.c index d7c03a06bb..3a3bed13b7 100644 --- a/src/add-ons/kernel/generic/mpu401/mpu401.c +++ b/src/add-ons/kernel/generic/mpu401/mpu401.c @@ -21,14 +21,15 @@ #include "mpu401_priv.h" /* ---------- - midi_create_device - + midi_create_device - ----- */ /*-----------------------------*/ /* Version 1 of mpu401 module */ /*-----------------------------*/ -static status_t -create_device(int port, void ** out_storage, uint32 workarounds, void (*interrupt_op)(int32 op, void * card), void * card) +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; @@ -39,50 +40,52 @@ create_device(int port, void ** out_storage, uint32 workarounds, void (*interrup mpu_device.V2 = FALSE; mpu_device.count = 1; mpu_device.interrupt_op = interrupt_op; - mpu_device.card = card; + mpu_device.card = card; - LOG(("create_device count= %ld, addrport 0x%x, workarounds: %d",mpu_device.count, mpu_device.addrport, mpu_device.workarounds)); + 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 + // 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)); *out_storage = (void *)mpuptr; - + return B_OK; } /*-----------------------------*/ /* Version 2 of mpu401 module */ /*-----------------------------*/ -static status_t -create_device_v2(int port, void ** out_storage, uint32 workarounds, void (*interrupt_op)(int32 op, void * card), void * card) +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; - LOG(("v2: create_device, **out_storage %p ,workarounds %ld ,void *card %p\n",out_storage, workarounds, card)); - - // 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. + // 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 // data is transfered via the global ports. - // If the ports are created in the midi server, then the port id's + // If the ports are created in the midi server, then the port id's // should be known in this hook call. - // If the ports are created in this hook call, the the port id's + // If the ports are created in this hook call, the the port id's // should be returned to the midi server. - // One version of read/write hook functions are used for both v1, v2. Therefore, in - // those calls, it needs to be known whether the mididata is to be read/written - // to a buffer, or to the port. + // One version of read/write hook functions are used for both v1, v2. + // Therefore, in those calls, it needs to be known whether the mididata + // is to be read/written to a buffer, or to the port. mpu_device.addrport = port; mpu_device.workarounds = workarounds; - mpu_device.V2 = TRUE; - mpu_device.count =1; - mpu_device.card = card; + mpu_device.V2 = TRUE; + mpu_device.count = 1; + mpu_device.card = card; + LOG(("create_device count= %ld, addrport 0x%x, workarounds: %d", + mpu_device.count, mpu_device.addrport, mpu_device.workarounds)); mpuptr = (mpu401device*)malloc(sizeof(mpu401device)); memcpy(mpuptr, &mpu_device, sizeof(mpu_device)); @@ -93,18 +96,19 @@ create_device_v2(int port, void ** out_storage, uint32 workarounds, void (*inter /* ---------- - midi_delete_device + midi_delete_device ----- */ -static status_t +static status_t delete_device(void * storage) -{ +{ mpu401device * mpu_device = (mpu401device *)storage; - LOG(("device->addrport= 0x%x count= %ld\n",mpu_device->addrport, mpu_device->count)); - LOG(("delete_device: *storage:%p\n",storage)); + LOG(("device->addrport= 0x%x count= %ld\n", + mpu_device->addrport, mpu_device->count)); + LOG(("delete_device: *storage:%p\n", storage)); + + free(mpu_device); // free the memory allocated in create_device - free(mpu_device); // free the memory allocated in create_device - return B_OK; } @@ -112,78 +116,106 @@ delete_device(void * storage) midi_open - handle open() calls ----- */ -static status_t +static status_t midi_open(void * storage, uint32 flags, void ** out_cookie) { char semname[25]; - int ack_byte; + int ack_byte; mpu401device * mpu_device = (mpu401device *)storage; - 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)); + 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; - + switch (mpu_device->workarounds){ - case 0x11020004: // This is still required for Creative Audigy, Audidy2 + case 0x11020004: // Still required for Creative Audigy, Audigy2 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); + Write_MPU401(mpu_device->addrport, UARTCMD, + mpu_device->workarounds, MPU401_RESET); snooze(30000); - Write_MPU401(mpu_device->addrport, UARTCMD, mpu_device->workarounds, MPU401_RESET); + Write_MPU401(mpu_device->addrport, UARTCMD, + mpu_device->workarounds, MPU401_RESET); snooze(30000); - ack_byte = Read_MPU401(mpu_device->addrport, UARTDATA, mpu_device->workarounds); + 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); + Write_MPU401(mpu_device->addrport, UARTCMD, + mpu_device->workarounds, MPU401_UART); snooze(30000); - ack_byte = Read_MPU401(mpu_device->addrport, UARTDATA, mpu_device->workarounds ); + 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 0x14121712: + PRINT(("reset MPU401\n")); + Write_MPU401(mpu_device->addrport, UARTDATA, + mpu_device->workarounds, 0x00); + 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, UARTDATA, + mpu_device->workarounds, 0x00); + snooze(30000); + 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)); + break; case 1: - // Some devices are always in UART mode + // Some devices are always in UART mode PRINT(("already in UART mode\n")); break; default: - PRINT(("Unknown workaround value: %d\n", mpu_device->workarounds)); + PRINT(("Unknown workaround: %d\n", mpu_device->workarounds)); break; } //end switch // Create Read semaphore for midi-in data 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->addrport); mpu_device->writesemaphore = create_sem(1, semname); - + // clear midi-in buffer - mbuf_bytes=0; + mbuf_bytes = 0; mbuf_current=0; mbuf_start=0; //Enable midi interrupts - mpu_device->interrupt_op(B_MPU_401_ENABLE_CARD_INT, mpu_device->card ); - + 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; } /* ---------- midi_close - handle close() calls ----- */ -static status_t +static status_t midi_close(void * cookie) { mpu401device * mpu_device = (mpu401device *)cookie; @@ -192,13 +224,13 @@ midi_close(void * cookie) return B_ERROR; //Disable soundcard midi interrupts - mpu_device->interrupt_op(B_MPU_401_DISABLE_CARD_INT, mpu_device->card ); + 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); + atomic_add(&mpu_device->count, -1); PRINT(("midi_close() done (count = %lu)\n", mpu_device->count)); return B_OK; @@ -207,7 +239,7 @@ midi_close(void * cookie) /* ---------- midi_free - free up allocated memory ----- */ -static status_t +static status_t midi_free(void * cookie) { LOG(("midi_free()\n")); @@ -217,7 +249,7 @@ midi_free(void * cookie) /* ---------- midi_control - handle control() calls ----- */ -static status_t +static status_t midi_control(void * cookie, uint32 op, void * data, size_t len) { //mpu401device *mpu_device = (mpu401device *)cookie; @@ -231,13 +263,13 @@ midi_control(void * cookie, uint32 op, void * data, size_t len) /* ---------- midi_read - handle read() calls ----- */ -static status_t +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; this reads and returns the data from a buffer */ - unsigned char *data; + unsigned char *data; unsigned int i; size_t count; cpu_status status; @@ -249,29 +281,29 @@ midi_read(void *cookie, off_t pos, void *buffer, size_t *num_bytes) i=0; *num_bytes=0; - bestat = acquire_sem_etc ( mpu_device->readsemaphore, 1, B_CAN_INTERRUPT, 0); + bestat = acquire_sem_etc(mpu_device->readsemaphore, 1, + B_CAN_INTERRUPT, 0); if (bestat == B_INTERRUPTED) { //PRINT(("acquire_sem B_INTERRUPTED!\n")); - return B_INTERRUPTED; + 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) { + return B_INTERRUPTED; + } else { status = lock(); *(data+i) = mpubuffer[mbuf_start]; i++; - mbuf_start++; // pointer to data in ringbuffer + 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 + mbuf_start = 0; //wraparound of ringbuffer + *num_bytes = 1; // How many bytes are being returned in buffer if (mbuf_bytes>0) - mbuf_bytes--; // bytes read from buffer, so decrement buffer count + mbuf_bytes--; // bytes read from buffer, so decrement buffer count unlock(status); //PRINT(("bytes in buffer: %d\n",mbuf_bytes)); - } + } return B_OK; } @@ -279,7 +311,7 @@ midi_read(void *cookie, off_t pos, void *buffer, size_t *num_bytes) /* ---------- midi_write - handle write() calls ----- */ -static status_t +static status_t midi_write(void * cookie, off_t pos, const void * data, size_t * num_bytes) { unsigned char *bufdata; @@ -287,71 +319,83 @@ midi_write(void * cookie, off_t pos, const void * data, size_t * num_bytes) size_t count; mpu401device *mpu_device = (mpu401device *)cookie; - bufdata = (unsigned char*)data; /* Pointer to midi data buffer */ + bufdata = (unsigned char*)data; /* Pointer to midi data buffer */ count = *num_bytes; - + /* 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)); + /*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; iaddrport, UARTCMD, mpu_device->workarounds) & MPU401_OK2WR)); - Write_MPU401(mpu_device->addrport, UARTDATA, mpu_device->workarounds, *(bufdata+i)); - } + while ((Read_MPU401(mpu_device->addrport, UARTCMD, + mpu_device->workarounds) & MPU401_OK2WR)); - *num_bytes = 0; + Write_MPU401(mpu_device->addrport, UARTDATA, + mpu_device->workarounds, *(bufdata+i)); + } + + *num_bytes = 0; release_sem(mpu_device->writesemaphore); return B_OK; } /* ---------- - interrupt_hook - handle interrupts for mpu401 data + interrupt_hook - handle interrupts for mpu401 data ----- */ -static bool +static bool interrupt_hook(void * cookie) { status_t bestat; mpu401device *mpu_device = (mpu401device *)cookie; - - //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->addrport, UARTCMD, mpu_device->workarounds) & MPU401_OK2RD) == 0) { + /* Only for deep debugging..will slow things down */ + //PRINT(("irq! port: 0x%x\n",mpu_device->addrport)); + + /* 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->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; - - 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); - - return TRUE; //B_INVOKE_SCHEDULER - } + + /* store midi data byte into buffer */ + mpubuffer[mbuf_current] = Read_MPU401(mpu_device->addrport, + UARTDATA, mpu_device->workarounds); + 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); + + return TRUE; //B_INVOKE_SCHEDULER + } + /* No midi data from this interrupt */ - return FALSE; //B_UNHANDLED_INTERRUPT + return FALSE; //B_UNHANDLED_INTERRUPT } /*-----------------------------------------------------------------*/ -uchar -Read_MPU401(unsigned int addrport, const char cmdtype, unsigned int workarounds) +uchar +Read_MPU401(unsigned int addrport, const char cmdtype, + unsigned int workarounds) { uchar mpudatabyte; cpu_status status; unsigned int regptr; - - //PRINT(("read workaround 0x%x\n",workarounds)); /* Only for deep debugging..will slow things down */ + + /* Only for deep debugging..will slow things down */ + //PRINT(("read workaround 0x%x\n",workarounds)); switch (workarounds) { case 0x11020004: /* Creative Audigy Gameport */ regptr = (((I_MPU1 + cmdtype) << 16) & PTR_ADDRESS_MASK); - status = lock(); + status = lock(); gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA or CMD */ mpudatabyte = gPCI->read_io_32(addrport + D_DATA); unlock(status); @@ -359,42 +403,55 @@ Read_MPU401(unsigned int addrport, const char cmdtype, unsigned int workarounds) case 0x11020005: /* Creative Audigy LiveDrive */ regptr = (((I_MPU2 + cmdtype) << 16) & PTR_ADDRESS_MASK); - status = lock(); + 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(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 ); + case 0x14121712: + status = lock(); + mpudatabyte = gPCI->read_io_8(addrport + cmdtype); unlock(status); break; - case 0x11020005: /* Creative Audigy LiveDrive */ + default: + mpudatabyte = gISA->read_io_8(addrport + cmdtype); + break; + } + return 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; + + 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 ); + status = lock(); + gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA2 or CMD2 */ + gPCI->write_io_32(addrport + D_DATA, mpudatabyte ); + unlock(status); + break; + + case 0x14121712: + status = lock(); + gPCI->write_io_8(addrport + cmdtype, mpudatabyte); unlock(status); break; @@ -402,7 +459,7 @@ Write_MPU401(unsigned int addrport, const char cmdtype, unsigned int workarounds gISA->write_io_8(addrport + cmdtype, mpudatabyte); break; } - return B_OK; + return B_OK; } @@ -412,7 +469,7 @@ static status_t std_ops(int32 op, ...) { switch(op) { - + case B_MODULE_INIT: LOG_CREATE(); @@ -423,19 +480,19 @@ std_ops(int32 op, ...) 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); put_module(B_PCI_MODULE_NAME); PRINT(("B_MODULE_UNINIT\n")); return B_OK; - + default: return B_ERROR; } } -static generic_mpu401_module mpu401_module = +static generic_mpu401_module mpu401_module = { { B_MPU_401_MODULE_NAME, @@ -453,8 +510,8 @@ static generic_mpu401_module mpu401_module = interrupt_hook }; -// Module v2 seems to be undocumented -static generic_mpu401_module mpu401_module2 = +// Module v2 seems to be undocumented +static generic_mpu401_module mpu401_module2 = { { "generic/mpu401/v2", @@ -480,7 +537,7 @@ _EXPORT generic_mpu401_module *modules[] = }; spinlock locked = B_SPINLOCK_INITIALIZER; -cpu_status +cpu_status lock(void) { cpu_status status = disable_interrupts(); @@ -488,7 +545,7 @@ lock(void) return status; } -void +void unlock(cpu_status status) { release_spinlock(&locked);