1 /*- 2 * Copyright (c) 1999 Seigo Tanimura 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <dev/sound/midi/midi.h> 30 #include <dev/sound/chip.h> 31 #include <dev/sound/pci/csareg.h> 32 #include <machine/cpufunc.h> 33 34 static devclass_t midi_devclass; 35 36 #ifndef DDB 37 #undef DDB 38 #define DDB(x) 39 #endif /* DDB */ 40 41 #define CSAMIDI_RESET 0xff 42 #define CSAMIDI_UART 0x3f 43 #define CSAMIDI_ACK 0xfe 44 45 #define CSAMIDI_STATMASK 0xc0 46 #define CSAMIDI_OUTPUTBUSY 0x40 47 #define CSAMIDI_INPUTBUSY 0x80 48 49 #define CSAMIDI_TRYDATA 50 50 #define CSAMIDI_DELAY 25000 51 52 extern synthdev_info midisynth_op_desc; 53 54 /* These are the synthesizer and the midi interface information. */ 55 static struct synth_info csamidi_synthinfo = { 56 "CS461x MIDI", 57 0, 58 SYNTH_TYPE_MIDI, 59 0, 60 0, 61 128, 62 128, 63 128, 64 SYNTH_CAP_INPUT, 65 }; 66 67 static struct midi_info csamidi_midiinfo = { 68 "CS461x MIDI", 69 0, 70 0, 71 0, 72 }; 73 74 /* 75 * These functions goes into csamidi_op_desc to get called 76 * from sound.c. 77 */ 78 79 static int csamidi_probe(device_t dev); 80 static int csamidi_attach(device_t dev); 81 82 static d_ioctl_t csamidi_ioctl; 83 static driver_intr_t csamidi_intr; 84 static midi_callback_t csamidi_callback; 85 86 /* Here is the parameter structure per a device. */ 87 struct csamidi_softc { 88 device_t dev; /* device information */ 89 mididev_info *devinfo; /* midi device information */ 90 struct csa_bridgeinfo *binfo; /* The state of the parent. */ 91 92 struct resource *io; /* Base of io map */ 93 int io_rid; /* Io map resource ID */ 94 struct resource *mem; /* Base of memory map */ 95 int mem_rid; /* Memory map resource ID */ 96 struct resource *irq; /* Irq */ 97 int irq_rid; /* Irq resource ID */ 98 void *ih; /* Interrupt cookie */ 99 100 int fflags; /* File flags */ 101 }; 102 103 typedef struct csamidi_softc *sc_p; 104 105 /* These functions are local. */ 106 static void csamidi_startplay(sc_p scp); 107 static void csamidi_xmit(sc_p scp); 108 static int csamidi_reset(sc_p scp); 109 static int csamidi_status(sc_p scp); 110 static int csamidi_command(sc_p scp, u_int32_t value); 111 static int csamidi_readdata(sc_p scp); 112 static int csamidi_writedata(sc_p scp, u_int32_t value); 113 static u_int32_t csamidi_readio(sc_p scp, u_long offset); 114 static void csamidi_writeio(sc_p scp, u_long offset, u_int32_t data); 115 static u_int32_t csamidi_readmem(sc_p scp, u_long offset); 116 static void csamidi_writemem(sc_p scp, u_long offset, u_int32_t data); 117 static int csamidi_allocres(sc_p scp, device_t dev); 118 static void csamidi_releaseres(sc_p scp, device_t dev); 119 120 /* 121 * This is the device descriptor for the midi device. 122 */ 123 static mididev_info csamidi_op_desc = { 124 "CS461x midi", 125 126 SNDCARD_MPU401, 127 128 NULL, 129 NULL, 130 NULL, 131 NULL, 132 csamidi_ioctl, 133 NULL, 134 135 csamidi_callback, 136 137 MIDI_BUFFSIZE, /* Queue Length */ 138 139 0, /* XXX This is not an *audio* device! */ 140 }; 141 142 /* 143 * Here are the main functions to interact to the user process. 144 */ 145 146 static int 147 csamidi_probe(device_t dev) 148 { 149 char *s; 150 sc_p scp; 151 struct sndcard_func *func; 152 153 /* The parent device has already been probed. */ 154 155 func = device_get_ivars(dev); 156 if (func == NULL || func->func != SCF_MIDI) 157 return (ENXIO); 158 159 s = "CS461x Midi Interface"; 160 161 scp = device_get_softc(dev); 162 bzero(scp, sizeof(*scp)); 163 scp->io_rid = CS461x_IO_OFFSET; 164 scp->mem_rid = CS461x_MEM_OFFSET; 165 scp->irq_rid = 0; 166 167 device_set_desc(dev, s); 168 return (0); 169 } 170 171 static int 172 csamidi_attach(device_t dev) 173 { 174 sc_p scp; 175 mididev_info *devinfo; 176 struct sndcard_func *func; 177 int unit; 178 179 scp = device_get_softc(dev); 180 unit = device_get_unit(dev); 181 func = device_get_ivars(dev); 182 scp->binfo = func->varinfo; 183 184 /* Allocate the resources. */ 185 if (csamidi_allocres(scp, dev)) { 186 csamidi_releaseres(scp, dev); 187 return (ENXIO); 188 } 189 190 /* Fill the softc. */ 191 scp->dev = dev; 192 scp->devinfo = devinfo = &midi_info[unit]; 193 194 /* Fill the midi info. */ 195 bcopy(&csamidi_op_desc, devinfo, sizeof(csamidi_op_desc)); 196 midiinit(devinfo, dev); 197 devinfo->flags = 0; 198 bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc)); 199 snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at irq %d", 200 (int)rman_get_start(scp->irq)); 201 202 /* Init the queue. */ 203 devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1; 204 midibuf_init(&devinfo->midi_dbuf_in); 205 midibuf_init(&devinfo->midi_dbuf_out); 206 207 /* Increase the number of midi devices. */ 208 nmidi++; 209 210 /* Enable interrupt. */ 211 if (bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, csamidi_intr, scp, &scp->ih)) { 212 csamidi_releaseres(scp, dev); 213 return (ENXIO); 214 } 215 216 /* Reset the interface. */ 217 csamidi_reset(scp); 218 219 return (0); 220 } 221 222 static int 223 csamidi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) 224 { 225 sc_p scp; 226 mididev_info *devinfo; 227 int unit; 228 struct synth_info *synthinfo; 229 struct midi_info *midiinfo; 230 231 unit = MIDIUNIT(i_dev); 232 233 if (unit >= nmidi + nsynth) { 234 DEB(printf("csamidi_ioctl: unit %d does not exist.\n", unit)); 235 return (ENXIO); 236 } 237 238 devinfo = get_mididev_info(i_dev, &unit); 239 if (devinfo == NULL) { 240 DEB(printf("csamidi_ioctl: unit %d is not configured.\n", unit)); 241 return (ENXIO); 242 } 243 scp = devinfo->softc; 244 245 switch (cmd) { 246 case SNDCTL_SYNTH_INFO: 247 synthinfo = (struct synth_info *)arg; 248 if (synthinfo->device > nmidi + nsynth || synthinfo->device != unit) 249 return (ENXIO); 250 bcopy(&csamidi_synthinfo, synthinfo, sizeof(csamidi_synthinfo)); 251 synthinfo->device = unit; 252 return (0); 253 break; 254 case SNDCTL_MIDI_INFO: 255 midiinfo = (struct midi_info *)arg; 256 if (midiinfo->device > nmidi + nsynth || midiinfo->device != unit) 257 return (ENXIO); 258 bcopy(&csamidi_midiinfo, midiinfo, sizeof(csamidi_midiinfo)); 259 midiinfo->device = unit; 260 return (0); 261 break; 262 default: 263 return (ENOSYS); 264 } 265 /* NOTREACHED */ 266 return (EINVAL); 267 } 268 269 static void 270 csamidi_intr(void *arg) 271 { 272 sc_p scp; 273 u_char c; 274 mididev_info *devinfo; 275 276 scp = (sc_p)arg; 277 devinfo = scp->devinfo; 278 279 /* Read the received data. */ 280 while ((csamidi_status(scp) & MIDSR_RBE) == 0) { 281 /* Receive the data. */ 282 c = (u_char)csamidi_readdata(scp); 283 /* Queue into the passthru buffer and start transmitting if we can. */ 284 if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) { 285 midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c, sizeof(c)); 286 devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR); 287 } 288 /* Queue if we are reading. Discard an active sensing. */ 289 if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe) 290 midibuf_input_intr(&devinfo->midi_dbuf_in, &c, sizeof(c)); 291 } 292 293 /* Transmit out data. */ 294 if ((devinfo->flags & MIDI_F_WRITING) != 0 && (csamidi_status(scp) & MIDSR_TBF) == 0) 295 csamidi_xmit(scp); 296 297 /* Invoke the upper layer. */ 298 midi_intr(devinfo); 299 } 300 301 static int 302 csamidi_callback(mididev_info *d, int reason) 303 { 304 int unit; 305 sc_p scp; 306 307 if (d == NULL) { 308 DEB(printf("csamidi_callback: device not configured.\n")); 309 return (ENXIO); 310 } 311 312 unit = d->unit; 313 scp = d->softc; 314 315 switch (reason & MIDI_CB_REASON_MASK) { 316 case MIDI_CB_START: 317 if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) == 0) 318 /* Begin recording. */ 319 d->flags |= MIDI_F_READING; 320 if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0) 321 /* Start playing. */ 322 csamidi_startplay(scp); 323 break; 324 case MIDI_CB_STOP: 325 case MIDI_CB_ABORT: 326 if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) != 0) 327 /* Stop recording. */ 328 d->flags &= ~MIDI_F_READING; 329 if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) != 0) 330 /* Stop Playing. */ 331 d->flags &= ~MIDI_F_WRITING; 332 break; 333 } 334 335 return (0); 336 } 337 338 /* 339 * The functions below here are the libraries for the above ones. 340 */ 341 342 /* 343 * Starts to play the data in the output queue. 344 * Call this at >=splclock. 345 */ 346 static void 347 csamidi_startplay(sc_p scp) 348 { 349 mididev_info *devinfo; 350 351 devinfo = scp->devinfo; 352 353 /* Can we play now? */ 354 if (devinfo->midi_dbuf_out.rl == 0) 355 return; 356 357 devinfo->flags |= MIDI_F_WRITING; 358 csamidi_xmit(scp); 359 } 360 361 static void 362 csamidi_xmit(sc_p scp) 363 { 364 register mididev_info *devinfo; 365 register midi_dbuf *dbuf; 366 u_char c; 367 368 devinfo = scp->devinfo; 369 370 /* See which source to use. */ 371 if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0)) 372 dbuf = &devinfo->midi_dbuf_out; 373 else 374 dbuf = &devinfo->midi_dbuf_passthru; 375 376 /* Transmit the data in the queue. */ 377 while ((devinfo->flags & MIDI_F_WRITING) != 0 && (csamidi_status(scp) & MIDSR_TBF) == 0) { 378 /* Do we have the data to transmit? */ 379 if (dbuf->rl == 0) { 380 /* Stop playing. */ 381 devinfo->flags &= ~MIDI_F_WRITING; 382 break; 383 } else { 384 /* Send the data. */ 385 midibuf_output_intr(dbuf, &c, sizeof(c)); 386 csamidi_writedata(scp, c); 387 /* We are playing now. */ 388 devinfo->flags |= MIDI_F_WRITING; 389 } 390 } 391 } 392 393 /* Reset midi. */ 394 static int 395 csamidi_reset(sc_p scp) 396 { 397 int i, resp; 398 399 /* Reset the midi. */ 400 resp = 0; 401 for (i = 0 ; i < CSAMIDI_TRYDATA ; i++) { 402 resp = csamidi_command(scp, MIDCR_MRST); 403 if (resp == 0) 404 break; 405 } 406 if (resp != 0) 407 return (1); 408 for (i = 0 ; i < CSAMIDI_TRYDATA ; i++) { 409 resp = csamidi_command(scp, MIDCR_TXE | MIDCR_RXE | MIDCR_RIE | MIDCR_TIE); 410 if (resp == 0) 411 break; 412 } 413 if (resp != 0) 414 return (1); 415 416 DELAY(CSAMIDI_DELAY); 417 418 return (0); 419 } 420 421 /* Reads the status. */ 422 static int 423 csamidi_status(sc_p scp) 424 { 425 return csamidi_readio(scp, BA0_MIDSR); 426 } 427 428 /* Writes a command. */ 429 static int 430 csamidi_command(sc_p scp, u_int32_t value) 431 { 432 csamidi_writeio(scp, BA0_MIDCR, value); 433 434 return (0); 435 } 436 437 /* Reads a byte of data. */ 438 static int 439 csamidi_readdata(sc_p scp) 440 { 441 u_int status; 442 443 /* Is the interface ready to read? */ 444 status = csamidi_status(scp); 445 if ((status & MIDSR_RBE) != 0) 446 /* The interface is busy. */ 447 return (-EAGAIN); 448 449 return (int)csamidi_readio(scp, BA0_MIDRP) & 0xff; 450 } 451 452 /* Writes a byte of data. */ 453 static int 454 csamidi_writedata(sc_p scp, u_int32_t value) 455 { 456 u_int status; 457 458 /* Is the interface ready to write? */ 459 status = csamidi_status(scp); 460 if ((status & MIDSR_TBF) != 0) 461 /* The interface is busy. */ 462 return (EAGAIN); 463 464 csamidi_writeio(scp, BA0_MIDWP, value & 0xff); 465 466 return (0); 467 } 468 469 static u_int32_t 470 csamidi_readio(sc_p scp, u_long offset) 471 { 472 if (offset < BA0_AC97_RESET) 473 return bus_space_read_4(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), offset) & 0xffffffff; 474 else 475 return (0); 476 } 477 478 static void 479 csamidi_writeio(sc_p scp, u_long offset, u_int32_t data) 480 { 481 if (offset < BA0_AC97_RESET) 482 bus_space_write_4(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), offset, data); 483 } 484 485 static u_int32_t 486 csamidi_readmem(sc_p scp, u_long offset) 487 { 488 return bus_space_read_4(rman_get_bustag(scp->mem), rman_get_bushandle(scp->mem), offset) & 0xffffffff; 489 } 490 491 static void 492 csamidi_writemem(sc_p scp, u_long offset, u_int32_t data) 493 { 494 bus_space_write_4(rman_get_bustag(scp->mem), rman_get_bushandle(scp->mem), offset, data); 495 } 496 497 /* Allocates resources. */ 498 static int 499 csamidi_allocres(sc_p scp, device_t dev) 500 { 501 if (scp->io == NULL) { 502 scp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &scp->io_rid, 0, ~0, CS461x_IO_SIZE, RF_ACTIVE); 503 if (scp->io == NULL) 504 return (1); 505 } 506 if (scp->mem == NULL) { 507 scp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &scp->mem_rid, 0, ~0, CS461x_MEM_SIZE, RF_ACTIVE); 508 if (scp->mem == NULL) 509 return (1); 510 } 511 if (scp->irq == NULL) { 512 scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 513 if (scp->irq == NULL) 514 return (1); 515 } 516 517 return (0); 518 } 519 520 /* Releases resources. */ 521 static void 522 csamidi_releaseres(sc_p scp, device_t dev) 523 { 524 if (scp->irq != NULL) { 525 bus_release_resource(dev, SYS_RES_IRQ, scp->irq_rid, scp->irq); 526 scp->irq = NULL; 527 } 528 if (scp->io != NULL) { 529 bus_release_resource(dev, SYS_RES_MEMORY, scp->io_rid, scp->io); 530 scp->io = NULL; 531 } 532 if (scp->mem != NULL) { 533 bus_release_resource(dev, SYS_RES_MEMORY, scp->mem_rid, scp->mem); 534 scp->mem = NULL; 535 } 536 } 537 538 static device_method_t csamidi_methods[] = { 539 /* Device interface */ 540 DEVMETHOD(device_probe , csamidi_probe ), 541 DEVMETHOD(device_attach, csamidi_attach), 542 543 { 0, 0 }, 544 }; 545 546 static driver_t csamidi_driver = { 547 "midi", 548 csamidi_methods, 549 sizeof(struct csamidi_softc), 550 }; 551 552 DRIVER_MODULE(csamidi, csa, csamidi_driver, midi_devclass, 0, 0); 553