1 /* $OpenBSD: fmsradio.c,v 1.7 2021/11/23 00:17:59 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Vladimir Popov <jumbo@narod.ru> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* Device Driver for FM Tuners attached to FM801 */ 30 31 /* Currently supported tuners: 32 * o SoundForte RadioLink SF64-PCR PCI Radio Card 33 * o SoundForte Quad X-treme SF256-PCP-R PCI Sound Card with FM Radio 34 * o SoundForte Theatre X-treme 5.1 SF256-PCS-R PCI Sound Card with FM Radio 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/device.h> 41 #include <sys/errno.h> 42 #include <sys/ioctl.h> 43 #include <sys/audioio.h> 44 #include <sys/radioio.h> 45 46 #include <machine/bus.h> 47 48 #include <dev/pci/pcireg.h> 49 #include <dev/pci/pcivar.h> 50 #include <dev/pci/pcidevs.h> 51 52 #include <dev/audio_if.h> 53 #include <dev/radio_if.h> 54 55 #include <dev/ic/ac97.h> 56 57 #include <dev/pci/fmsreg.h> 58 #include <dev/pci/fmsvar.h> 59 60 #include <dev/ic/tea5757.h> 61 62 #define TUNER_UNKNOWN 0 63 #define TUNER_SF256PCPR 1 64 #define TUNER_SF64PCR 2 65 #define TUNER_SF256PCS 3 66 67 #define SF64PCR_CAPS RADIO_CAPS_DETECT_STEREO | \ 68 RADIO_CAPS_DETECT_SIGNAL | \ 69 RADIO_CAPS_SET_MONO | \ 70 RADIO_CAPS_HW_SEARCH | \ 71 RADIO_CAPS_HW_AFC | \ 72 RADIO_CAPS_LOCK_SENSITIVITY 73 74 #define SF256PCPR_CAPS RADIO_CAPS_DETECT_STEREO | \ 75 RADIO_CAPS_SET_MONO | \ 76 RADIO_CAPS_HW_SEARCH | \ 77 RADIO_CAPS_HW_AFC | \ 78 RADIO_CAPS_LOCK_SENSITIVITY 79 80 #define SF256PCS_CAPS RADIO_CAPS_SET_MONO | \ 81 RADIO_CAPS_HW_SEARCH | \ 82 RADIO_CAPS_HW_AFC | \ 83 RADIO_CAPS_LOCK_SENSITIVITY 84 85 #define PCR_WREN_ON 0 86 #define PCR_WREN_OFF FM_IO_PIN1 87 #define PCR_CLOCK_ON FM_IO_PIN0 88 #define PCR_CLOCK_OFF 0 89 #define PCR_DATA_ON FM_IO_PIN2 90 #define PCR_DATA_OFF 0 91 92 #define PCR_SIGNAL 0x80 93 #define PCR_STEREO 0x80 94 #define PCR_INFO_SIGNAL (1 << 24) 95 #define PCR_INFO_STEREO (1 << 25) 96 97 #define PCPR_WREN_ON 0 98 #define PCPR_WREN_OFF FM_IO_PIN2 99 #define PCPR_CLOCK_ON FM_IO_PIN0 100 #define PCPR_CLOCK_OFF 0 101 #define PCPR_DATA_ON FM_IO_PIN1 102 #define PCPR_DATA_OFF 0 103 #define PCPR_INFO_STEREO 0x04 104 105 #define PCS_WREN_ON 0 106 #define PCS_WREN_OFF FM_IO_PIN2 107 #define PCS_CLOCK_ON FM_IO_PIN3 108 #define PCS_CLOCK_OFF 0 109 #define PCS_DATA_ON FM_IO_PIN1 110 #define PCS_DATA_OFF 0 111 112 /* 113 * Function prototypes 114 */ 115 void fmsradio_set_mute(struct fms_softc *); 116 117 void sf64pcr_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t); 118 void sf64pcr_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t); 119 void sf64pcr_write_bit(bus_space_tag_t, bus_space_handle_t, bus_size_t, int); 120 u_int32_t sf64pcr_hw_read(bus_space_tag_t, bus_space_handle_t, bus_size_t); 121 int sf64pcr_probe(struct fms_softc *); 122 123 void sf256pcpr_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t); 124 void sf256pcpr_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t); 125 void sf256pcpr_write_bit(bus_space_tag_t, bus_space_handle_t, bus_size_t, int); 126 u_int32_t sf256pcpr_hw_read(bus_space_tag_t, bus_space_handle_t, bus_size_t); 127 int sf256pcpr_probe(struct fms_softc *); 128 129 void sf256pcs_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t); 130 void sf256pcs_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t); 131 void sf256pcs_write_bit(bus_space_tag_t, bus_space_handle_t, bus_size_t, int); 132 u_int32_t sf256pcs_hw_read(bus_space_tag_t, bus_space_handle_t, bus_size_t); 133 int sf256pcs_probe(struct fms_softc *); 134 135 int fmsradio_get_info(void *, struct radio_info *); 136 int fmsradio_set_info(void *, struct radio_info *); 137 int fmsradio_search(void *, int); 138 139 struct radio_hw_if fmsradio_hw_if = { 140 NULL, /* open */ 141 NULL, /* close */ 142 fmsradio_get_info, 143 fmsradio_set_info, 144 fmsradio_search 145 }; 146 147 struct fmsradio_if { 148 int type; /* Card type */ 149 150 int mute; 151 u_int8_t vol; 152 u_int32_t freq; 153 u_int32_t stereo; 154 u_int32_t lock; 155 156 struct tea5757_t tea; 157 }; 158 159 int 160 fmsradio_attach(struct fms_softc *sc) 161 { 162 struct fmsradio_if *r; 163 164 r = malloc(sizeof(struct fmsradio_if), M_DEVBUF, M_NOWAIT); 165 if (r == NULL) { 166 printf("%s: cannot allocate memory for FM tuner config\n", 167 sc->sc_dev.dv_xname); 168 return TUNER_UNKNOWN; 169 } 170 171 sc->radio = r; 172 r->tea.iot = sc->sc_iot; 173 r->tea.ioh = sc->sc_ioh; 174 r->tea.offset = FM_IO_CTL; 175 r->tea.flags = sc->sc_dev.dv_cfdata->cf_flags; 176 r->vol = 0; 177 r->mute = 0; 178 r->freq = MIN_FM_FREQ; 179 r->stereo = TEA5757_STEREO; 180 r->lock = TEA5757_S030; 181 182 r->type = TUNER_UNKNOWN; 183 if ((r->type = sf64pcr_probe(sc)) == TUNER_SF64PCR) 184 printf("%s: SF64-PCR FM Radio\n", sc->sc_dev.dv_xname); 185 else if ((r->type = sf256pcpr_probe(sc)) == TUNER_SF256PCPR) 186 printf("%s: SF256-PCP-R FM Radio\n", sc->sc_dev.dv_xname); 187 else if ((r->type = sf256pcs_probe(sc)) == TUNER_SF256PCS) 188 printf("%s: SF256-PCS-R FM Radio\n", sc->sc_dev.dv_xname); 189 else 190 return TUNER_UNKNOWN; 191 192 fmsradio_set_mute(sc); 193 radio_attach_mi(&fmsradio_hw_if, sc, &sc->sc_dev); 194 return r->type; 195 } 196 197 /* SF256-PCS specific routines */ 198 int 199 sf256pcs_probe(struct fms_softc *sc) 200 { 201 struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio; 202 u_int32_t freq; 203 204 radio->tea.init = sf256pcs_init; 205 radio->tea.rset = sf256pcs_rset; 206 radio->tea.write_bit = sf256pcs_write_bit; 207 radio->tea.read = sf256pcs_hw_read; 208 209 tea5757_set_freq(&radio->tea, radio->stereo, 210 radio->lock, radio->freq); 211 freq = tea5757_decode_freq(sf256pcs_hw_read(radio->tea.iot, 212 radio->tea.ioh, radio->tea.offset), 213 radio->tea.flags & TEA5757_TEA5759); 214 if (freq != radio->freq) 215 return TUNER_UNKNOWN; 216 217 return TUNER_SF256PCS; 218 } 219 220 u_int32_t 221 sf256pcs_hw_read(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t offset) 222 { 223 u_int32_t res = 0ul; 224 u_int16_t i, d; 225 226 d = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3) | PCS_WREN_OFF; 227 228 /* Now read data in */ 229 d |= FM_IO_GPIO_IN(PCS_DATA_ON) | PCS_DATA_ON; 230 231 bus_space_write_2(iot, ioh, offset, d | PCS_CLOCK_OFF); 232 233 /* Read the register */ 234 i = 24; 235 while (i--) { 236 res <<= 1; 237 bus_space_write_2(iot, ioh, offset, d | PCS_CLOCK_ON); 238 bus_space_write_2(iot, ioh, offset, d | PCS_CLOCK_OFF); 239 res |= bus_space_read_2(iot, ioh, offset) & 240 PCS_DATA_ON ? 1 : 0; 241 } 242 243 return (res & (TEA5757_DATA | TEA5757_FREQ)); 244 } 245 246 void 247 sf256pcs_write_bit(bus_space_tag_t iot, bus_space_handle_t ioh, 248 bus_size_t off, int bit) 249 { 250 u_int16_t data, wren; 251 252 wren = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3); 253 wren |= PCS_WREN_ON; 254 data = bit ? PCPR_DATA_ON : PCS_DATA_OFF; 255 256 bus_space_write_2(iot, ioh, off, PCS_CLOCK_OFF | wren | data); 257 bus_space_write_2(iot, ioh, off, PCS_CLOCK_ON | wren | data); 258 bus_space_write_2(iot, ioh, off, PCS_CLOCK_OFF | wren | data); 259 } 260 261 void 262 sf256pcs_init(bus_space_tag_t iot, bus_space_handle_t ioh, 263 bus_size_t offset, u_int32_t d) 264 { 265 d = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3); 266 d |= PCS_WREN_ON | PCS_DATA_OFF | PCS_CLOCK_OFF; 267 268 bus_space_write_2(iot, ioh, offset, d); 269 bus_space_write_2(iot, ioh, offset, d); 270 } 271 272 void 273 sf256pcs_rset(bus_space_tag_t iot, bus_space_handle_t ioh, 274 bus_size_t offset, u_int32_t d) 275 { 276 d = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3); 277 d |= PCS_WREN_OFF | PCS_DATA_OFF | PCS_CLOCK_OFF; 278 279 bus_space_write_2(iot, ioh, offset, d); 280 bus_space_write_2(iot, ioh, offset, d); 281 } 282 283 /* SF256-PCP-R specific routines */ 284 int 285 sf256pcpr_probe(struct fms_softc *sc) 286 { 287 struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio; 288 u_int32_t freq; 289 290 radio->tea.init = sf256pcpr_init; 291 radio->tea.rset = sf256pcpr_rset; 292 radio->tea.write_bit = sf256pcpr_write_bit; 293 radio->tea.read = sf256pcpr_hw_read; 294 295 tea5757_set_freq(&radio->tea, radio->stereo, 296 radio->lock, radio->freq); 297 freq = tea5757_decode_freq(sf256pcpr_hw_read(radio->tea.iot, 298 radio->tea.ioh, radio->tea.offset), 299 radio->tea.flags & TEA5757_TEA5759); 300 if (freq != radio->freq) 301 return TUNER_UNKNOWN; 302 303 return TUNER_SF256PCPR; 304 } 305 306 u_int32_t 307 sf256pcpr_hw_read(bus_space_tag_t iot, bus_space_handle_t ioh, 308 bus_size_t offset) 309 { 310 u_int32_t res = 0ul; 311 u_int16_t i, d; 312 313 d = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(PCPR_DATA_ON | FM_IO_PIN3); 314 315 /* Now read data in */ 316 d |= PCPR_WREN_OFF | PCPR_DATA_ON; 317 318 bus_space_write_2(iot, ioh, offset, d | PCPR_CLOCK_OFF); 319 320 /* Read the register */ 321 i = 24; 322 while (i--) { 323 res <<= 1; 324 bus_space_write_2(iot, ioh, offset, d | PCPR_CLOCK_ON); 325 bus_space_write_2(iot, ioh, offset, d | PCPR_CLOCK_OFF); 326 res |= bus_space_read_2(iot, ioh, offset) & 327 PCPR_DATA_ON ? 1 : 0; 328 } 329 330 return (res & (TEA5757_DATA | TEA5757_FREQ)); 331 } 332 333 void 334 sf256pcpr_write_bit(bus_space_tag_t iot, bus_space_handle_t ioh, 335 bus_size_t off, int bit) 336 { 337 u_int16_t data, wren; 338 339 wren = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3) | PCPR_WREN_ON; 340 data = bit ? PCPR_DATA_ON : PCPR_DATA_OFF; 341 342 bus_space_write_2(iot, ioh, off, PCPR_CLOCK_OFF | wren | data); 343 bus_space_write_2(iot, ioh, off, PCPR_CLOCK_ON | wren | data); 344 bus_space_write_2(iot, ioh, off, PCPR_CLOCK_OFF | wren | data); 345 } 346 347 void 348 sf256pcpr_init(bus_space_tag_t iot, bus_space_handle_t ioh, 349 bus_size_t offset, u_int32_t d) 350 { 351 d = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3); 352 d |= PCPR_WREN_ON | PCPR_DATA_OFF | PCPR_CLOCK_OFF; 353 354 bus_space_write_2(iot, ioh, offset, d); 355 bus_space_write_2(iot, ioh, offset, d); 356 } 357 358 void 359 sf256pcpr_rset(bus_space_tag_t iot, bus_space_handle_t ioh, 360 bus_size_t offset, u_int32_t d) 361 { 362 d = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3); 363 d |= PCPR_WREN_OFF | PCPR_DATA_OFF | PCPR_CLOCK_OFF; 364 365 bus_space_write_2(iot, ioh, offset, d); 366 bus_space_write_2(iot, ioh, offset, d); 367 } 368 369 /* SF64-PCR specific routines */ 370 int 371 sf64pcr_probe(struct fms_softc *sc) 372 { 373 struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio; 374 u_int32_t freq; 375 376 radio->tea.init = sf64pcr_init; 377 radio->tea.rset = sf64pcr_rset; 378 radio->tea.write_bit = sf64pcr_write_bit; 379 radio->tea.read = sf64pcr_hw_read; 380 381 tea5757_set_freq(&radio->tea, radio->stereo, 382 radio->lock, radio->freq); 383 freq = tea5757_decode_freq(sf64pcr_hw_read(radio->tea.iot, 384 radio->tea.ioh, radio->tea.offset), 385 radio->tea.flags & TEA5757_TEA5759); 386 if (freq != radio->freq) 387 return TUNER_UNKNOWN; 388 389 return TUNER_SF64PCR; 390 } 391 392 u_int32_t 393 sf64pcr_hw_read(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t offset) 394 { 395 u_int32_t res = 0ul; 396 u_int16_t d, i, ind = 0; 397 398 d = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(PCR_DATA_ON | FM_IO_PIN3); 399 400 /* Now read data in */ 401 d |= PCR_WREN_OFF | PCR_DATA_ON; 402 403 bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_OFF); 404 DELAY(4); 405 406 /* Read the register */ 407 i = 23; 408 while (i--) { 409 bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_ON); 410 DELAY(4); 411 412 bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_OFF); 413 DELAY(4); 414 415 res |= bus_space_read_2(iot, ioh, offset) & PCR_DATA_ON ? 1 : 0; 416 res <<= 1; 417 } 418 419 bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_ON); 420 DELAY(4); 421 422 i = bus_space_read_1(iot, ioh, offset); 423 ind = i & PCR_SIGNAL ? (1 << 1) : (0 << 1); /* Tuning */ 424 425 bus_space_write_2(iot, ioh, offset, d | PCR_CLOCK_OFF); 426 427 i = bus_space_read_2(iot, ioh, offset); 428 ind |= i & PCR_STEREO ? (1 << 0) : (0 << 0); /* Mono */ 429 res |= i & PCR_DATA_ON ? (1 << 0) : (0 << 0); 430 431 return (res & (TEA5757_DATA | TEA5757_FREQ)) | (ind << 24); 432 } 433 434 void 435 sf64pcr_write_bit(bus_space_tag_t iot, bus_space_handle_t ioh, 436 bus_size_t off, int bit) 437 { 438 u_int16_t data, wren; 439 440 wren = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3) | PCR_WREN_ON; 441 data = bit ? PCR_DATA_ON : PCR_DATA_OFF; 442 443 bus_space_write_2(iot, ioh, off, PCR_CLOCK_OFF | wren | data); 444 DELAY(4); 445 bus_space_write_2(iot, ioh, off, PCR_CLOCK_ON | wren | data); 446 DELAY(4); 447 bus_space_write_2(iot, ioh, off, PCR_CLOCK_OFF | wren | data); 448 DELAY(4); 449 } 450 451 void 452 sf64pcr_init(bus_space_tag_t iot, bus_space_handle_t ioh, 453 bus_size_t offset, u_int32_t d) 454 { 455 d = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3); 456 d |= PCR_WREN_ON | PCR_DATA_ON | PCR_CLOCK_OFF; 457 458 bus_space_write_2(iot, ioh, offset, d); 459 DELAY(4); 460 } 461 462 void 463 sf64pcr_rset(bus_space_tag_t iot, bus_space_handle_t ioh, 464 bus_size_t offset, u_int32_t d) 465 { 466 /* Do nothing */ 467 return; 468 } 469 470 471 /* Common tuner routines */ 472 /* 473 * Mute/unmute 474 */ 475 void 476 fmsradio_set_mute(struct fms_softc *sc) 477 { 478 struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio; 479 u_int16_t v, mute, unmute; 480 481 switch (radio->type) { 482 case TUNER_SF256PCS: 483 mute = FM_IO_GPIO(FM_IO_PIN1 | FM_IO_PIN2 | FM_IO_PIN3); 484 unmute = mute | PCS_WREN_OFF; 485 break; 486 case TUNER_SF256PCPR: 487 mute = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3); 488 unmute = mute | PCPR_WREN_OFF; 489 break; 490 case TUNER_SF64PCR: 491 mute = FM_IO_GPIO_ALL | FM_IO_GPIO_IN(FM_IO_PIN3); 492 unmute = mute | PCR_WREN_OFF; 493 break; 494 default: 495 return; 496 } 497 v = (radio->mute || !radio->vol) ? mute : unmute; 498 bus_space_write_2(radio->tea.iot, radio->tea.ioh, 499 radio->tea.offset, v); 500 DELAY(64); 501 bus_space_write_2(radio->tea.iot, radio->tea.ioh, 502 radio->tea.offset, v); 503 } 504 505 int 506 fmsradio_get_info(void *v, struct radio_info *ri) 507 { 508 struct fms_softc *sc = v; 509 struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio; 510 u_int32_t buf; 511 512 ri->mute = radio->mute; 513 ri->volume = radio->vol ? 255 : 0; 514 ri->stereo = radio->stereo == TEA5757_STEREO ? 1 : 0; 515 ri->lock = tea5757_decode_lock(radio->lock); 516 517 switch (radio->type) { 518 case TUNER_SF256PCS: 519 ri->caps = SF256PCS_CAPS; 520 buf = sf256pcs_hw_read(radio->tea.iot, radio->tea.ioh, 521 radio->tea.offset); 522 ri->info = 0; /* UNSUPPORTED */ 523 break; 524 case TUNER_SF256PCPR: 525 ri->caps = SF256PCPR_CAPS; 526 buf = sf256pcpr_hw_read(radio->tea.iot, radio->tea.ioh, 527 radio->tea.offset); 528 ri->info = bus_space_read_2(radio->tea.iot, radio->tea.ioh, 529 FM_VOLUME) == PCPR_INFO_STEREO ? 530 RADIO_INFO_STEREO : 0; 531 break; 532 case TUNER_SF64PCR: 533 ri->caps = SF64PCR_CAPS; 534 buf = sf64pcr_hw_read(radio->tea.iot, radio->tea.ioh, 535 radio->tea.offset); 536 ri->info = buf & PCR_INFO_SIGNAL ? 0 : RADIO_INFO_SIGNAL; 537 ri->info |= buf & PCR_INFO_STEREO ? 0 : RADIO_INFO_STEREO; 538 break; 539 default: 540 return EINVAL; 541 } 542 543 ri->freq = radio->freq = tea5757_decode_freq(buf, 544 sc->sc_dev.dv_cfdata->cf_flags & TEA5757_TEA5759); 545 546 fmsradio_set_mute(sc); 547 548 /* UNSUPPORTED */ 549 ri->rfreq = 0; 550 551 return (0); 552 } 553 554 int 555 fmsradio_set_info(void *v, struct radio_info *ri) 556 { 557 struct fms_softc *sc = v; 558 struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio; 559 560 radio->mute = ri->mute ? 1 : 0; 561 radio->vol = ri->volume ? 255 : 0; 562 radio->stereo = ri->stereo ? TEA5757_STEREO: TEA5757_MONO; 563 radio->lock = tea5757_encode_lock(ri->lock); 564 ri->freq = radio->freq = tea5757_set_freq(&radio->tea, 565 radio->lock, radio->stereo, ri->freq); 566 fmsradio_set_mute(sc); 567 568 return (0); 569 } 570 571 int 572 fmsradio_search(void *v, int f) 573 { 574 struct fms_softc *sc = v; 575 struct fmsradio_if *radio = (struct fmsradio_if *)sc->radio; 576 577 tea5757_search(&radio->tea, radio->lock, 578 radio->stereo, f); 579 fmsradio_set_mute(sc); 580 581 return (0); 582 } 583