1 /* 2 * Copyright 2003-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * A module driver for the generic mpu401 midi interface. 6 * 7 * Author: 8 * Greg Crain (gsc70@comcast.net) 9 * 10 * mpu401.c 11 */ 12 13 14 #include <ISA.h> 15 #include <KernelExport.h> 16 #include <OS.h> 17 #include <midi_driver.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include "debug.h" 22 #include "mpu401_priv.h" 23 24 25 /* ---------- 26 midi_create_device - 27 ----- */ 28 /*-----------------------------*/ 29 /* Version 1 of mpu401 module */ 30 /*-----------------------------*/ 31 32 static status_t 33 create_device(int port, void ** out_storage, uint32 workarounds, 34 void (*interrupt_op)(int32 op, void * card), void * card) 35 { 36 mpu401device mpu_device; 37 mpu401device *mpuptr; 38 39 /* fill the structure with specific info from caller */ 40 mpu_device.addrport = port; 41 mpu_device.workarounds = workarounds; 42 mpu_device.V2 = FALSE; 43 mpu_device.count = 1; 44 mpu_device.interrupt_op = interrupt_op; 45 mpu_device.card = card; 46 47 LOG(("create_device count= %ld, addrport 0x%x, workarounds: %d", 48 mpu_device.count, mpu_device.addrport, mpu_device.workarounds)); 49 50 // basically, each call to create device allocates memory for 51 //a structure with the specific device info. The pointer to this is 52 // returned back to calling driver 53 mpuptr = (mpu401device*)malloc (sizeof(mpu401device)); 54 memcpy(mpuptr, &mpu_device, sizeof(mpu_device)); 55 *out_storage = (void *)mpuptr; 56 57 return B_OK; 58 } 59 60 61 /*-----------------------------*/ 62 /* Version 2 of mpu401 module */ 63 /*-----------------------------*/ 64 65 static status_t 66 create_device_v2(int port, void ** out_storage, uint32 workarounds, 67 void (*interrupt_op)(int32 op, void * card), void * card) 68 { 69 mpu401device *mpuptr; 70 mpu401device mpu_device; 71 72 // not sure exactly how v2 of the module works. I think that two ports 73 // are created. One for midi in data, and another for midi out data. 74 // Instead of transfering data using a buffer and pointer, the midi 75 // data is transfered via the global ports. 76 // If the ports are created in the midi server, then the port id's 77 // should be known in this hook call. 78 // If the ports are created in this hook call, the the port id's 79 // should be returned to the midi server. 80 81 // One version of read/write hook functions are used for both v1, v2. 82 // Therefore, in those calls, it needs to be known whether the mididata 83 // is to be read/written to a buffer, or to the port. 84 85 mpu_device.addrport = port; 86 mpu_device.workarounds = workarounds; 87 mpu_device.V2 = TRUE; 88 mpu_device.count = 1; 89 mpu_device.card = card; 90 91 LOG(("create_device count= %ld, addrport 0x%x, workarounds: %d", 92 mpu_device.count, mpu_device.addrport, mpu_device.workarounds)); 93 94 mpuptr = (mpu401device*)malloc(sizeof(mpu401device)); 95 memcpy(mpuptr, &mpu_device, sizeof(mpu_device)); 96 *out_storage = (void *)mpuptr; 97 98 return B_OK; 99 } 100 101 102 /* ---------- 103 midi_delete_device 104 ----- */ 105 static status_t 106 delete_device(void * storage) 107 { 108 mpu401device * mpu_device = (mpu401device *)storage; 109 110 LOG(("device->addrport= 0x%x count= %ld\n", 111 mpu_device->addrport, mpu_device->count)); 112 LOG(("delete_device: *storage:%p\n", storage)); 113 114 free(mpu_device); // free the memory allocated in create_device 115 116 return B_OK; 117 } 118 119 120 /* ---------- 121 midi_open - handle open() calls 122 ----- */ 123 124 static status_t 125 midi_open(void * storage, uint32 flags, void ** out_cookie) 126 { 127 char semname[25]; 128 int ack_byte; 129 mpu401device * mpu_device = (mpu401device *)storage; 130 131 LOG(("open() flags: %ld, *storage: %p, **out_cookie: %p\n", flags, 132 storage, out_cookie)); 133 LOG(("open: device->addrport 0x%x ,workarounds 0x%x\n", 134 mpu_device->addrport, mpu_device->workarounds)); 135 136 // the undocumented V2 module is not complete 137 // we will allow the device to be created since some drivers depend on it 138 // but will return an error if the actual midi device is opened: 139 if (mpu_device->V2 == TRUE) 140 return B_ERROR; 141 142 switch (mpu_device->workarounds) { 143 case 0x11020004: // Still required for Creative Audigy, Audigy2 144 case 0x11020005: 145 case 0: 146 // don't know the current mpu state 147 PRINT(("reset MPU401\n")); 148 Write_MPU401(mpu_device->addrport, UARTCMD, 149 mpu_device->workarounds, MPU401_RESET); 150 snooze(30000); 151 Write_MPU401(mpu_device->addrport, UARTCMD, 152 mpu_device->workarounds, MPU401_RESET); 153 snooze(30000); 154 ack_byte = Read_MPU401(mpu_device->addrport, UARTDATA, 155 mpu_device->workarounds); 156 PRINT(("enable UART mode\n")); 157 Write_MPU401(mpu_device->addrport, UARTCMD, 158 mpu_device->workarounds, MPU401_UART); 159 snooze(30000); 160 ack_byte = Read_MPU401(mpu_device->addrport, UARTDATA, 161 mpu_device->workarounds); 162 PRINT(("port cmd ack is 0x%x\n", ack_byte)); 163 *out_cookie = mpu_device; 164 break; 165 case 0x14121712: 166 PRINT(("reset MPU401\n")); 167 Write_MPU401(mpu_device->addrport, UARTDATA, 168 mpu_device->workarounds, 0x00); 169 snooze(30000); 170 Write_MPU401(mpu_device->addrport, UARTCMD, 171 mpu_device->workarounds, MPU401_RESET); 172 snooze(30000); 173 ack_byte = Read_MPU401(mpu_device->addrport, UARTDATA, 174 mpu_device->workarounds); 175 PRINT(("enable UART mode\n")); 176 Write_MPU401(mpu_device->addrport, UARTDATA, 177 mpu_device->workarounds, 0x00); 178 snooze(30000); 179 Write_MPU401(mpu_device->addrport, UARTCMD, 180 mpu_device->workarounds, MPU401_UART); 181 snooze(30000); 182 ack_byte = Read_MPU401(mpu_device->addrport, UARTDATA, 183 mpu_device->workarounds); 184 PRINT(("port cmd ack is 0x%x\n", ack_byte)); 185 break; 186 case 1: 187 // Some devices are always in UART mode 188 PRINT(("already in UART mode\n")); 189 break; 190 default: 191 PRINT(("Unknown workaround: %d\n", mpu_device->workarounds)); 192 break; 193 } //end switch 194 195 // Create Read semaphore for midi-in data 196 sprintf(semname, "mpu401:%04x:read_sem", mpu_device->addrport); 197 mpu_device->readsemaphore = create_sem(0, semname); 198 199 // Create Write semaphore for midi-out data 200 sprintf(semname,"mpu401:%04x:write_sem", mpu_device->addrport); 201 mpu_device->writesemaphore = create_sem(1, semname); 202 203 // clear midi-in buffer 204 mbuf_bytes = 0; 205 mbuf_current = 0; 206 mbuf_start = 0; 207 208 //Enable midi interrupts 209 mpu_device->interrupt_op(B_MPU_401_ENABLE_CARD_INT, mpu_device->card); 210 211 if ((mpu_device->readsemaphore > B_OK) 212 && (mpu_device->writesemaphore > B_OK)) { 213 atomic_add(&mpu_device->count, 1); 214 PRINT(("midi_open() done (count = %x)\n", open_count)); 215 return B_OK; 216 } 217 return B_ERROR; 218 } 219 220 221 /* ---------- 222 midi_close - handle close() calls 223 ----- */ 224 static status_t 225 midi_close(void * cookie) 226 { 227 mpu401device * mpu_device = (mpu401device *)cookie; 228 229 if (mpu_device->count <= 0) 230 return B_ERROR; 231 232 //Disable soundcard midi interrupts 233 mpu_device->interrupt_op(B_MPU_401_DISABLE_CARD_INT, mpu_device->card); 234 235 // Delete the semaphores 236 delete_sem(mpu_device->readsemaphore); 237 delete_sem(mpu_device->writesemaphore); 238 239 atomic_add(&mpu_device->count, -1); 240 PRINT(("midi_close() done (count = %" B_PRId32 ")\n", mpu_device->count)); 241 242 return B_OK; 243 } 244 245 246 /* ---------- 247 midi_free - free up allocated memory 248 ----- */ 249 static status_t 250 midi_free(void * cookie) 251 { 252 LOG(("midi_free()\n")); 253 return B_OK; 254 } 255 256 257 /* ---------- 258 midi_control - handle control() calls 259 ----- */ 260 static status_t 261 midi_control(void * cookie, uint32 op, void * data, size_t len) 262 { 263 //mpu401device *mpu_device = (mpu401device *)cookie; 264 265 /* I don't think this is ever called ...*/ 266 LOG(("midi_control()\n")); 267 return B_OK; 268 } 269 270 271 /* ---------- 272 midi_read - handle read() calls 273 ----- */ 274 static status_t 275 midi_read(void *cookie, off_t pos, void *buffer, size_t *num_bytes) 276 { 277 /* The actual midi data is read from the device in the interrupt handler; 278 this reads and returns the data from a buffer */ 279 280 unsigned char *data; 281 unsigned int i; 282 cpu_status status __attribute__((unused)); 283 status_t bestat; 284 mpu401device *mpu_device = (mpu401device *)cookie; 285 286 data = (unsigned char*)buffer; 287 288 i = 0; 289 *num_bytes = 0; 290 bestat = acquire_sem_etc(mpu_device->readsemaphore, 1, 291 B_CAN_INTERRUPT, 0); 292 if (bestat == B_INTERRUPTED) { 293 //PRINT(("acquire_sem B_INTERRUPTED!\n")); 294 return B_INTERRUPTED; 295 } 296 if (bestat != B_OK) { 297 TRACE(("acquire_sem not B_OK %d\n",(int)bestat)); 298 *num_bytes = 1; 299 return B_INTERRUPTED; 300 } else { 301 #ifdef __HAIKU__ 302 if (user_memcpy(data+i, &(mpubuffer[mbuf_start]), 303 sizeof(unsigned char)) == B_OK) { 304 #else 305 status = lock(); 306 *(data+i) = mpubuffer[mbuf_start]; 307 #endif 308 i++; 309 mbuf_start++; // pointer to data in ringbuffer 310 if (mbuf_start >= (MBUF_ELEMENTS-1)) 311 mbuf_start = 0; //wraparound of ringbuffer 312 *num_bytes = 1; // How many bytes are being returned in buffer 313 if (mbuf_bytes > 0) 314 mbuf_bytes--; // bytes read from buffer, so decrement buffer count 315 #ifdef __HAIKU__ 316 } 317 #else 318 unlock(status); 319 #endif 320 //PRINT(("bytes in buffer: %d\n",mbuf_bytes)); 321 } 322 323 return B_OK; 324 } 325 326 327 /* ---------- 328 midi_write - handle write() calls 329 ----- */ 330 static status_t 331 midi_write(void * cookie, off_t pos, const void * data, size_t * num_bytes) 332 { 333 unsigned char *bufdata; 334 uint32 i; 335 size_t count; 336 337 mpu401device *mpu_device = (mpu401device *)cookie; 338 bufdata = (unsigned char*)data; /* Pointer to midi data buffer */ 339 count = *num_bytes; 340 341 /* Only for deep debugging..will slow things down */ 342 /*PRINT(("write %d bytes, addrport 0x%x, workarounds 0x%x\n", 343 (int)count, mpu_device->addrport, mpu_device->workarounds));*/ 344 345 acquire_sem(mpu_device->writesemaphore); 346 for (i = 0; i < count; i++) { 347 // wait until device is ready 348 while ((Read_MPU401(mpu_device->addrport, UARTCMD, 349 mpu_device->workarounds) & MPU401_OK2WR)); 350 351 Write_MPU401(mpu_device->addrport, UARTDATA, 352 mpu_device->workarounds, *(bufdata+i)); 353 } 354 355 *num_bytes = 0; 356 release_sem(mpu_device->writesemaphore); 357 358 return B_OK; 359 } 360 361 362 /* ---------- 363 interrupt_hook - handle interrupts for mpu401 data 364 ----- */ 365 static bool 366 interrupt_hook(void * cookie) 367 { 368 mpu401device *mpu_device = (mpu401device *)cookie; 369 370 /* Only for deep debugging..will slow things down */ 371 //PRINT(("irq! port: 0x%x\n",mpu_device->addrport)); 372 373 /* Input data is available when bit 7 of the Status port is zero. 374 Conversely, when bit 7 is is a one, no MIDI data is available. 375 Reading from the data port will often clear the interrupt signal 376 depending on the sound card. */ 377 378 if ((Read_MPU401(mpu_device->addrport, UARTCMD, 379 mpu_device->workarounds) & MPU401_OK2RD) == 0) { 380 /* Okay, midi data waiting to be read from device */ 381 if (mbuf_current >= (MBUF_ELEMENTS-1)) 382 mbuf_current = 0; 383 384 /* store midi data byte into buffer */ 385 mpubuffer[mbuf_current] = Read_MPU401(mpu_device->addrport, 386 UARTDATA, mpu_device->workarounds); 387 mbuf_current++; /* pointer to next blank byte */ 388 mbuf_bytes++; /* increment count of midi data bytes */ 389 390 release_sem_etc(mpu_device->readsemaphore, 1, B_DO_NOT_RESCHEDULE); 391 392 return TRUE; //B_INVOKE_SCHEDULER 393 } 394 395 /* No midi data from this interrupt */ 396 return FALSE; //B_UNHANDLED_INTERRUPT 397 } 398 399 400 /*-----------------------------------------------------------------*/ 401 402 uchar 403 Read_MPU401(unsigned int addrport, const char cmdtype, 404 unsigned int workarounds) 405 { 406 uchar mpudatabyte; 407 cpu_status status; 408 unsigned int regptr; 409 410 /* Only for deep debugging..will slow things down */ 411 //PRINT(("read workaround 0x%x\n",workarounds)); 412 switch (workarounds) { 413 case 0x11020004: /* Creative Audigy Gameport */ 414 regptr = (((I_MPU1 + cmdtype) << 16) & PTR_ADDRESS_MASK); 415 status = lock(); 416 gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA or CMD */ 417 mpudatabyte = gPCI->read_io_32(addrport + D_DATA); 418 unlock(status); 419 break; 420 421 case 0x11020005: /* Creative Audigy LiveDrive */ 422 regptr = (((I_MPU2 + cmdtype) << 16) & PTR_ADDRESS_MASK); 423 status = lock(); 424 gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA2 or CMD2 */ 425 mpudatabyte = gPCI->read_io_32(addrport + D_DATA); 426 unlock(status); 427 break; 428 429 case 0x14121712: 430 status = lock(); 431 mpudatabyte = gPCI->read_io_8(addrport + cmdtype); 432 unlock(status); 433 break; 434 435 default: 436 mpudatabyte = gISA->read_io_8(addrport + cmdtype); 437 break; 438 } 439 return mpudatabyte; 440 } 441 442 443 status_t 444 Write_MPU401(unsigned int addrport, const char cmdtype, 445 unsigned int workarounds, uchar mpudatabyte) 446 { 447 cpu_status status; 448 unsigned int regptr; 449 450 /* Only for deep debugging..will slow things down */ 451 //PRINT(("write workaround 0x%x at addr: 0x%x\n",workarounds,addrport)); 452 switch (workarounds) { 453 case 0x11020004: /* Creative Audigy Gameport */ 454 regptr = (((I_MPU1 + cmdtype) << 16) & PTR_ADDRESS_MASK); 455 status = lock(); 456 gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA or CMD */ 457 gPCI->write_io_32(addrport + D_DATA, mpudatabyte); 458 unlock(status); 459 break; 460 461 case 0x11020005: /* Creative Audigy LiveDrive */ 462 regptr = (((I_MPU2 + cmdtype) << 16) & PTR_ADDRESS_MASK); 463 status = lock(); 464 gPCI->write_io_32(addrport + D_PTR, regptr); /*DATA2 or CMD2 */ 465 gPCI->write_io_32(addrport + D_DATA, mpudatabyte); 466 unlock(status); 467 break; 468 469 case 0x14121712: 470 status = lock(); 471 gPCI->write_io_8(addrport + cmdtype, mpudatabyte); 472 unlock(status); 473 break; 474 475 default: 476 gISA->write_io_8(addrport + cmdtype, mpudatabyte); 477 break; 478 } 479 return B_OK; 480 } 481 482 483 /*-----------------------------------------------------------------*/ 484 485 static status_t 486 std_ops(int32 op, ...) 487 { 488 switch(op) { 489 490 case B_MODULE_INIT: 491 492 LOG_CREATE(); 493 PRINT(("B_MODULE_INIT\n")); 494 495 if (get_module(B_ISA_MODULE_NAME, (module_info **)&gISA) < B_OK) 496 return B_ERROR; 497 if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI) < B_OK) 498 return B_ERROR; 499 return B_OK; 500 501 case B_MODULE_UNINIT: 502 put_module(B_ISA_MODULE_NAME); 503 put_module(B_PCI_MODULE_NAME); 504 PRINT(("B_MODULE_UNINIT\n")); 505 return B_OK; 506 507 default: 508 return B_ERROR; 509 } 510 } 511 512 static generic_mpu401_module mpu401_module = 513 { 514 { 515 B_MPU_401_MODULE_NAME, 516 B_KEEP_LOADED /*0*/ , 517 std_ops 518 }, 519 create_device, 520 delete_device, 521 midi_open, 522 midi_close, 523 midi_free, 524 midi_control, 525 midi_read, 526 midi_write, 527 interrupt_hook 528 }; 529 530 // Module v2 seems to be undocumented 531 static generic_mpu401_module mpu401_module2 = 532 { 533 { 534 "generic/mpu401/v2", 535 0, 536 std_ops 537 }, 538 create_device_v2, 539 delete_device, 540 midi_open, 541 midi_close, 542 midi_free, 543 midi_control, 544 midi_read, 545 midi_write, 546 interrupt_hook 547 }; 548 549 _EXPORT generic_mpu401_module *modules[] = 550 { 551 &mpu401_module, 552 &mpu401_module2, 553 NULL 554 }; 555 556 spinlock locked = B_SPINLOCK_INITIALIZER; 557 cpu_status 558 lock(void) 559 { 560 cpu_status status = disable_interrupts(); 561 acquire_spinlock(&locked); 562 return status; 563 } 564 565 void 566 unlock(cpu_status status) 567 { 568 release_spinlock(&locked); 569 restore_interrupts(status); 570 } 571 572