1 /* $NetBSD: zz9k_ax.c,v 1.1 2023/05/03 13:49:30 phx Exp $ */ 2 3 /* 4 * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Alain Runa. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: zz9k_ax.c,v 1.1 2023/05/03 13:49:30 phx Exp $"); 33 34 /* miscellaneous */ 35 #include <sys/types.h> /* size_t */ 36 #include <sys/stdint.h> /* uintXX_t */ 37 #include <sys/stdbool.h> /* bool */ 38 39 /* driver(9) */ 40 #include <sys/param.h> /* NODEV */ 41 #include <sys/device.h> /* CFATTACH_DECL_NEW(), device_priv() */ 42 #include <sys/errno.h> /* . */ 43 44 /* bus_space(9) and zorro bus */ 45 #include <sys/bus.h> /* bus_space_xxx(), bus_space_xxx_t */ 46 #include <sys/cpu.h> /* kvtop() */ 47 #include <sys/systm.h> /* aprint_xxx() */ 48 49 /* mutex(9) */ 50 #include <sys/mutex.h> 51 52 /* Interrupt related */ 53 #include <sys/intr.h> 54 #include <amiga/amiga/isr.h> /* isr */ 55 56 /* audio(9) */ 57 #include <sys/audioio.h> 58 #include <dev/audio/audio_if.h> 59 60 /* zz9k related */ 61 #include <amiga/dev/zz9kvar.h> /* zz9kbus_attach_args */ 62 #include <amiga/dev/zz9kreg.h> /* ZZ9000 registers */ 63 #include "zz9k_ax.h" /* NZZ9K_AX */ 64 65 66 /* The allmighty softc structure */ 67 struct zzax_softc { 68 device_t sc_dev; 69 struct bus_space_tag sc_bst; 70 bus_space_tag_t sc_iot; 71 bus_space_handle_t sc_regh; 72 bus_space_handle_t sc_txbufh; 73 size_t sc_txbufsize; 74 75 struct isr sc_isr; 76 77 kmutex_t sc_lock; 78 kmutex_t sc_intr_lock; 79 }; 80 81 static int zzax_intr(void *arg); 82 static void zzax_set_param(struct zzax_softc *sc, uint16_t param, uint16_t val); 83 84 /* audio_hw_if */ 85 static int zzax_open(void *hdl, int flags); 86 static void zzax_close(void *hdl); 87 static int zzax_query_format(void *hdl, audio_format_query_t *afp); 88 static int zzax_set_format(void *hdl, int setmode, 89 const audio_params_t *play, const audio_params_t *rec, 90 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil); 91 static int zzax_round_blocksize(void *hdl, int bs, int mode, 92 const audio_params_t *param); 93 static int zzax_commit_settings(void *hdl); 94 static int zzax_init_output(void *hdl, void *buffer, int size); 95 static int zzax_init_input(void *hdl, void *buffer, int size); 96 static int zzax_start_output(void *hdl, void *block, int blksize, 97 void (*intr)(void*), void *intrarg); 98 static int zzax_start_input(void *hdl, void *block, int blksize, 99 void (*intr)(void*), void *intrarg); 100 static int zzax_halt_output(void *hdl); 101 static int zzax_halt_input(void *hdl); 102 static int zzax_speaker_ctl(void *hdl, int on); 103 static int zzax_getdev(void *hdl, struct audio_device *ret); 104 static int zzax_set_port(void *hdl, mixer_ctrl_t *mc); 105 static int zzax_get_port(void *hdl, mixer_ctrl_t *mc); 106 static int zzax_query_devinfo(void *hdl, mixer_devinfo_t *di); 107 #if 0 108 static void *zzax_allocm(void *hdl, int direction, size_t size); 109 static void zzax_freem(void *hdl, void *addr, size_t size); 110 #endif 111 static size_t zzax_round_buffersize(void *hdl, int direction, size_t bufsize); 112 static int zzax_get_props(void *hdl); 113 static int zzax_trigger_output(void *hdl, void *start, void *end, int blksize, 114 void (*intr)(void*), void *intrarg, const audio_params_t *param); 115 static int zzax_trigger_input(void *hdl, void *start, void *end, int blksize, 116 void (*intr)(void*), void *intrarg, const audio_params_t *param); 117 static int zzax_dev_ioctl(void *hdl, u_long cmd, void *addr, int flag, 118 struct lwp *l); 119 static void zzax_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread); 120 121 static const struct audio_hw_if zzax_hw_if = { 122 .open = zzax_open, 123 .close = zzax_close, 124 .query_format = zzax_query_format, 125 .set_format = zzax_set_format, 126 .round_blocksize = zzax_round_blocksize, 127 .commit_settings = zzax_commit_settings, 128 .init_output = zzax_init_output, 129 .init_input = zzax_init_input, 130 .start_output = zzax_start_output, 131 .start_input = zzax_start_input, 132 .halt_output = zzax_halt_output, 133 .halt_input = zzax_halt_input, 134 .speaker_ctl = zzax_speaker_ctl, 135 .getdev = zzax_getdev, 136 .set_port = zzax_set_port, 137 .get_port = zzax_get_port, 138 .query_devinfo = zzax_query_devinfo, 139 #if 0 140 .allocm = zzax_allocm, 141 .freem = zzax_freem, 142 #endif 143 .round_buffersize = zzax_round_buffersize, 144 .get_props = zzax_get_props, 145 .trigger_output = zzax_trigger_output, 146 .trigger_input = zzax_trigger_input, 147 .dev_ioctl = zzax_dev_ioctl, 148 .get_locks = zzax_get_locks 149 }; 150 151 static const struct audio_format zzax_format = { 152 .mode = AUMODE_PLAY, 153 .encoding = AUDIO_ENCODING_SLINEAR_BE, 154 .validbits = 16, 155 .precision = 16, 156 .channels = 2, 157 .channel_mask = AUFMT_STEREO, 158 .frequency_type = 0, 159 .frequency = {8000, 12000, 24000, 32000, 44100, 48000}, 160 .priority = 0 161 }; 162 163 static const struct audio_device zzax_device = { 164 .name = "ZZ9000AX", 165 .version = "1.13", 166 .config = "zzax" 167 }; 168 169 /* mixer sets */ 170 #define ZZAX_CHANNELS 0 171 172 /* mixer values */ 173 #define ZZAX_VOLUME 1 174 #define ZZAX_OUTPUT_CLASS 2 175 176 177 /* driver(9) essentials */ 178 static int zzax_match(device_t parent, cfdata_t match, void *aux); 179 static void zzax_attach(device_t parent, device_t self, void *aux); 180 CFATTACH_DECL_NEW(zz9k_ax, sizeof(struct zzax_softc), 181 zzax_match, zzax_attach, NULL, NULL); 182 183 184 /* Go ahead, make my day. */ 185 186 static int 187 zzax_match(device_t parent, cfdata_t match, void *aux) 188 { 189 struct zz9kbus_attach_args *bap = aux; 190 191 if (strcmp(bap->zzaa_name, "zz9k_ax") != 0) 192 return 0; 193 194 return 1; 195 } 196 197 static void 198 zzax_attach(device_t parent, device_t self, void *aux) 199 { 200 struct zz9kbus_attach_args *bap = aux; 201 struct zzax_softc *sc = device_private(self); 202 struct zz9k_softc *psc = device_private(parent); 203 204 sc->sc_dev = self; 205 sc->sc_bst.base = bap->zzaa_base; 206 sc->sc_bst.absm = &amiga_bus_stride_1; 207 sc->sc_iot = &sc->sc_bst; 208 sc->sc_regh = psc->sc_regh; 209 210 uint16_t config = ZZREG_R(ZZ9K_AUDIO_CONFIG); 211 aprint_normal(": ZZ9000AX %sdetected.\n", 212 (config == 0) ? "not " : ""); 213 aprint_normal_dev(sc->sc_dev, 214 "MNT ZZ9000AX driver is not functional yet.\n"); 215 216 aprint_debug_dev(sc->sc_dev, "[DEBUG] registers at %p/%p (pa/va)\n", 217 (void *)kvtop((void *)sc->sc_regh), 218 bus_space_vaddr(sc->sc_iot, sc->sc_regh)); 219 220 sc->sc_txbufsize = 0x10000; 221 uint32_t tx_buffer = psc->sc_zsize - sc->sc_txbufsize; 222 if (bus_space_map(sc->sc_iot, tx_buffer, sc->sc_txbufsize, 223 BUS_SPACE_MAP_LINEAR, &sc->sc_txbufh)) { 224 aprint_error(": Failed to map MNT ZZ9000AX audio tx buffer.\n"); 225 return; 226 } 227 228 aprint_normal_dev(sc->sc_dev, "base: %p/%p size: %i\n", 229 (void *)kvtop((void *)sc->sc_txbufh), 230 bus_space_vaddr(sc->sc_iot, sc->sc_txbufh), 231 sc->sc_txbufsize); 232 233 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 234 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 235 236 sc->sc_isr.isr_intr = zzax_intr; 237 sc->sc_isr.isr_arg = sc; 238 sc->sc_isr.isr_ipl = 6; 239 add_isr(&sc->sc_isr); 240 241 audio_attach_mi(&zzax_hw_if, sc, self); 242 243 uint16_t conf = ZZREG_R(ZZ9K_AUDIO_CONFIG); /* enable interrupt */ 244 ZZREG_W(ZZ9K_AUDIO_CONFIG, conf | ZZ9K_AUDIO_CONFIG_INT_AUDIO); 245 } 246 247 static int 248 zzax_intr(void *arg) 249 { 250 struct zzax_softc *sc = arg; 251 252 uint16_t conf = ZZREG_R(ZZ9K_CONFIG); 253 if ((conf & ZZ9K_CONFIG_INT_AUDIO) == 0) 254 return 0; 255 256 #if 0 257 uint16_t conf = ZZREG_R(ZZ9K_AUDIO_CONFIG); /* disable interrupt */ 258 ZZREG_W(ZZ9K_AUDIO_CONFIG, conf & ~ZZ9K_AUDIO_CONFIG_INT_AUDIO); 259 #endif 260 ZZREG_W(ZZ9K_CONFIG, ZZ9K_CONFIG_INT_ACK | ZZ9K_CONFIG_INT_ACK_AUDIO); 261 262 mutex_spin_enter(&sc->sc_intr_lock); 263 /* do stuff */ 264 mutex_spin_exit(&sc->sc_intr_lock); 265 266 #if 0 267 uint16_t conf = ZZREG_R(ZZ9K_AUDIO_CONFIG); /* enable interrupt */ 268 ZZREG_W(ZZ9K_AUDIO_CONFIG, conf | ZZ9K_AUDIO_CONFIG_INT_AUDIO); 269 #endif 270 271 return 1; 272 } 273 274 static void 275 zzax_set_param(struct zzax_softc *sc, uint16_t param, uint16_t val) 276 { 277 ZZREG_W(ZZ9K_AUDIO_PARAM, param); 278 ZZREG_W(ZZ9K_AUDIO_VAL, val); 279 ZZREG_W(ZZ9K_AUDIO_PARAM, 0); 280 } 281 282 int 283 zzax_open(void *hdl, int flags) 284 { 285 struct zzax_softc *sc = hdl; 286 uint32_t buffer = (uint32_t)bus_space_vaddr(sc->sc_iot, sc->sc_txbufh); 287 zzax_set_param(sc, ZZ9K_AP_TX_BUF_OFFS_HI, buffer >> 16); 288 zzax_set_param(sc, ZZ9K_AP_TX_BUF_OFFS_HI, buffer & 0xFFFF); 289 printf("zzax_open: %X\n", buffer); 290 return 0; 291 } 292 293 static void 294 zzax_close(void *hdl) 295 { 296 printf("zzax_close:\n"); 297 } 298 299 static int 300 zzax_query_format(void *hdl, audio_format_query_t *afp) 301 { 302 printf("zzax_query_format:\n"); 303 return audio_query_format(&zzax_format, 1, afp); 304 } 305 306 static int 307 zzax_set_format(void *hdl, int setmode, 308 const audio_params_t *play, const audio_params_t *rec, 309 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 310 { 311 struct zzax_softc *sc = hdl; 312 313 printf("zzax_set_format:\n"); 314 if (setmode & AUMODE_PLAY) { 315 zzax_set_param(sc, ZZ9K_AP_DSP_SET_LOWPASS, 23900); 316 printf("::play->sample_rate: %i\n", play->sample_rate); 317 printf("::play->encoding: %i\n", play->encoding); 318 printf("::play->precision: %i\n", play->precision); 319 printf("::play->validbits: %i\n", play->validbits); 320 printf("::play->channels: %i\n", play->channels); 321 } 322 323 if (setmode & AUMODE_RECORD) { 324 printf("::rec->sample_rate: %i\n", rec->sample_rate); 325 printf("::rec->encoding: %i\n", rec->encoding); 326 printf("::rec->precision: %i\n", rec->precision); 327 printf("::rec->validbits: %i\n", rec->validbits); 328 printf("::rec->channels: %i\n", rec->channels); 329 } 330 331 return 0; 332 } 333 334 static int 335 zzax_round_blocksize(void *hdl, int bs, int mode, const audio_params_t *param) 336 { 337 printf("zzax_round_blocksize:\n"); 338 printf("::bs: %i\n", bs); 339 printf("::mode: %i\n", mode); 340 printf("::param->sample_rate: %i\n", param->sample_rate); 341 printf("::param->encoding: %i\n", param->encoding); 342 printf("::param->precision: %i\n", param->precision); 343 printf("::param->validbits: %i\n", param->validbits); 344 printf("::param->channels: %i\n", param->channels); 345 346 return bs; 347 } 348 349 static int 350 zzax_commit_settings(void *hdl) 351 { 352 printf("zzax_commit_settings:\n"); 353 return 0; 354 } 355 356 static int 357 zzax_init_output(void *hdl, void *buffer, int size) 358 { 359 printf("zzax_init_output:\n"); 360 return 0; 361 } 362 363 static int 364 zzax_init_input(void *hdl, void *buffer, int size) 365 { 366 printf("zzax_init_input:\n"); 367 return 0; 368 } 369 370 static int 371 zzax_start_output(void *hdl, void *block, int blksize, 372 void (*intr)(void*), void *intrarg) 373 { 374 printf("zzax_start_output:\n"); 375 return 0; 376 } 377 378 static int 379 zzax_start_input(void *hdl, void *block, int blksize, 380 void (*intr)(void*), void *intrarg) 381 { 382 printf("zzax_start_input:\n"); 383 return ENXIO; 384 } 385 386 static int 387 zzax_halt_output(void *hdl) 388 { 389 printf("zzax_halt_output:\n"); 390 return 0; 391 } 392 393 static int 394 zzax_halt_input(void *hdl) 395 { 396 printf("zzax_halt_input:\n"); 397 return ENXIO; 398 } 399 400 static int 401 zzax_speaker_ctl(void *hdl, int on) 402 { 403 printf("zzax_speaker_ctl:\n"); 404 return 0; 405 } 406 407 static int 408 zzax_getdev(void *hdl, struct audio_device *ret) 409 { 410 *ret = zzax_device; 411 printf("zzax_getdev: %p\n", ret); 412 return 0; 413 } 414 415 static int 416 zzax_set_port(void *hdl, mixer_ctrl_t *mc) 417 { 418 printf("zzax_set_port:\n"); 419 return 0; 420 } 421 422 static int 423 zzax_get_port(void *hdl, mixer_ctrl_t *mc) 424 { 425 printf("zzax_get_port:\n"); 426 return 0; 427 } 428 429 static int 430 zzax_query_devinfo(void *hdl, mixer_devinfo_t *di) 431 { 432 switch(di->index) { 433 case ZZAX_CHANNELS: 434 strcpy(di->label.name, "speaker"); 435 di->type = AUDIO_MIXER_SET; 436 di->mixer_class = ZZAX_OUTPUT_CLASS; 437 di->prev = AUDIO_MIXER_LAST; 438 di->next = AUDIO_MIXER_LAST; 439 di->un.s.num_mem = 1; 440 strcpy(di->un.s.member[0].label.name, "channel0"); 441 di->un.s.member[0].mask = 0; 442 case ZZAX_VOLUME: 443 strcpy(di->label.name, "master"); 444 di->type = AUDIO_MIXER_VALUE; 445 di->mixer_class = ZZAX_OUTPUT_CLASS; 446 di->prev = AUDIO_MIXER_LAST; 447 di->next = AUDIO_MIXER_LAST; 448 di->un.v.num_channels = 1; 449 strcpy(di->un.v.units.name, "volume"); 450 break; 451 case ZZAX_OUTPUT_CLASS: 452 strcpy(di->label.name, "outputs"); 453 di->type = AUDIO_MIXER_CLASS; 454 di->mixer_class = ZZAX_OUTPUT_CLASS; 455 di->prev = AUDIO_MIXER_LAST; 456 di->next = AUDIO_MIXER_LAST; 457 break; 458 default: 459 return ENXIO; 460 } 461 462 printf("zzax_query_devinfo: %s\n", di->label.name); 463 464 return 0; 465 } 466 467 #if 0 468 static void* 469 zzax_allocm(void *hdl, int direction, size_t size) 470 { 471 472 } 473 474 static void 475 zzax_freem(void *hdl, void *addr, size_t size) 476 { 477 478 } 479 #endif 480 481 static size_t 482 zzax_round_buffersize(void *hdl, int direction, size_t bufsize) 483 { 484 printf("zzax_round_buffersize:\n"); 485 printf("::direction: %i\n", direction); 486 printf("::bufsize: %zu\n", bufsize); 487 return bufsize; 488 } 489 490 static int 491 zzax_get_props(void *hdl) 492 { 493 return AUDIO_PROP_PLAYBACK; 494 } 495 496 static int 497 zzax_trigger_output(void *hdl, void *start, void *end, int blksize, 498 void (*intr)(void*), void *intrarg, const audio_params_t *param) 499 { 500 printf("zzax_trigger_output:\n"); 501 return 0; 502 } 503 504 static int 505 zzax_trigger_input(void *hdl, void *start, void *end, int blksize, 506 void (*intr)(void*), void *intrarg, const audio_params_t *param) 507 { 508 return 0; 509 } 510 511 static int 512 zzax_dev_ioctl(void *hdl, u_long cmd, void *addr, int flag, struct lwp *l) 513 { 514 printf("zzax_dev_ioctl: %lu\n", cmd); 515 return 0; 516 } 517 518 static void 519 zzax_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread) 520 { 521 struct zzax_softc *sc = hdl; 522 *intr = &sc->sc_intr_lock; 523 *thread = &sc->sc_lock; 524 } 525