1/* $OpenBSD: bktr_os.c,v 1.37 2022/07/02 08:50:42 visa Exp $ */ 2/* $FreeBSD: src/sys/dev/bktr/bktr_os.c,v 1.20 2000/10/20 08:16:53 roger Exp $ */ 3 4/* 5 * This is part of the Driver for Video Capture Cards (Frame grabbers) 6 * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879 7 * chipset. 8 * Copyright Roger Hardiman and Amancio Hasty. 9 * 10 * bktr_os : This has all the Operating System dependant code, 11 * probe/attach and open/close/ioctl/read/mmap 12 * memory allocation 13 * PCI bus interfacing 14 * 15 * 16 */ 17 18/* 19 * 1. Redistributions of source code must retain the 20 * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman 21 * All rights reserved. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * This product includes software developed by Amancio Hasty and 34 * Roger Hardiman 35 * 4. The name of the author may not be used to endorse or promote products 36 * derived from this software without specific prior written permission. 37 * 38 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 40 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 42 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 44 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 46 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 47 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 48 * POSSIBILITY OF SUCH DAMAGE. 49 */ 50 51#define FIFO_RISC_DISABLED 0 52#define ALL_INTS_DISABLED 0 53 54#include "radio.h" 55 56#include <sys/param.h> 57#include <sys/systm.h> 58#include <sys/conf.h> 59#include <sys/uio.h> 60#include <sys/kernel.h> 61#include <sys/signalvar.h> 62#include <sys/mman.h> 63#include <sys/vnode.h> 64#if NRADIO > 0 65#include <sys/radioio.h> 66#include <dev/radio_if.h> 67#endif 68 69#include <uvm/uvm_extern.h> 70 71#include <sys/device.h> 72#include <dev/pci/pcivar.h> 73#include <dev/pci/pcireg.h> 74#include <dev/pci/pcidevs.h> 75 76#ifdef BKTR_DEBUG 77int bktr_debug = 1; 78#define DPR(x) (bktr_debug ? printf x : 0) 79#else 80#define DPR(x) 81#endif 82 83#include <dev/ic/bt8xx.h> /* OpenBSD location for .h files */ 84#include <dev/pci/bktr/bktr_reg.h> 85#include <dev/pci/bktr/bktr_tuner.h> 86#include <dev/pci/bktr/bktr_audio.h> 87#include <dev/pci/bktr/bktr_core.h> 88#include <dev/pci/bktr/bktr_os.h> 89 90#define IPL_VIDEO IPL_BIO /* XXX */ 91 92static int bktr_intr(void *arg) { return common_bktr_intr(arg); } 93 94#define bktr_open bktropen 95#define bktr_close bktrclose 96#define bktr_read bktrread 97#define bktr_write bktrwrite 98#define bktr_ioctl bktrioctl 99#define bktr_mmap bktrmmap 100 101int bktr_open(dev_t, int, int, struct proc *); 102int bktr_close(dev_t, int, int, struct proc *); 103int bktr_read(dev_t, struct uio *, int); 104int bktr_write(dev_t, struct uio *, int); 105int bktr_ioctl(dev_t, ioctl_cmd_t, caddr_t, int, struct proc *); 106paddr_t bktr_mmap(dev_t, off_t, int); 107 108static int bktr_probe(struct device *, void *, void *); 109static void bktr_attach(struct device *, struct device *, void *); 110 111const struct cfattach bktr_ca = { 112 sizeof(struct bktr_softc), bktr_probe, bktr_attach 113}; 114 115struct cfdriver bktr_cd = { 116 NULL, "bktr", DV_DULL 117}; 118 119#if NRADIO > 0 120/* for radio(4) */ 121int bktr_get_info(void *, struct radio_info *); 122int bktr_set_info(void *, struct radio_info *); 123 124const struct radio_hw_if bktr_hw_if = { 125 NULL, /* open */ 126 NULL, /* close */ 127 bktr_get_info, 128 bktr_set_info, 129 NULL /* search */ 130}; 131#endif 132 133int 134bktr_probe(struct device *parent, void *match, void *aux) 135{ 136 struct pci_attach_args *pa = aux; 137 138 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROOKTREE && 139 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT848 || 140 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT849 || 141 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT878 || 142 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT879)) 143 return 1; 144 145 return 0; 146} 147 148 149/* 150 * the attach routine. 151 */ 152static void 153bktr_attach(struct device *parent, struct device *self, void *aux) 154{ 155 bktr_ptr_t bktr; 156 u_int latency; 157 u_int fun; 158 unsigned int rev; 159 struct pci_attach_args *pa = aux; 160 pci_intr_handle_t ih; 161 const char *intrstr; 162 int retval; 163 int unit; 164 165 bktr = (bktr_ptr_t)self; 166 unit = bktr->bktr_dev.dv_unit; 167 bktr->dmat = pa->pa_dmat; 168 169 /* Enable Back-to-Back 170 XXX: check if all old DMA is stopped first (e.g. after warm 171 boot) */ 172 fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 173 DPR((" fun=%b", fun, PCI_COMMAND_STATUS_BITS)); 174 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 175 fun | PCI_COMMAND_BACKTOBACK_ENABLE); 176 177 /* 178 * map memory 179 */ 180 retval = pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM | 181 PCI_MAPREG_MEM_TYPE_32BIT, 0, &bktr->memt, &bktr->memh, NULL, 182 &bktr->obmemsz, 0); 183 DPR(("pci_mapreg_map: memt %lx, memh %lx, size %x\n", 184 bktr->memt, bktr->memh, bktr->obmemsz)); 185 if (retval) { 186 printf("%s: can't map mem space\n", bktr_name(bktr)); 187 return; 188 } 189 190 /* 191 * Disable the brooktree device 192 */ 193 OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED); 194 OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED); 195 196 /* 197 * map interrupt 198 */ 199 if (pci_intr_map(pa, &ih)) { 200 printf("%s: can't map interrupt\n", 201 bktr_name(bktr)); 202 return; 203 } 204 intrstr = pci_intr_string(pa->pa_pc, ih); 205 bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO, 206 bktr_intr, bktr, bktr->bktr_dev.dv_xname); 207 if (bktr->ih == NULL) { 208 printf("%s: can't establish interrupt", 209 bktr_name(bktr)); 210 if (intrstr != NULL) 211 printf(" at %s", intrstr); 212 printf("\n"); 213 return; 214 } 215 if (intrstr != NULL) 216 printf(": %s\n", intrstr); 217 218/* 219 * PCI latency timer. 32 is a good value for 4 bus mastering slots, if 220 * you have more than four, then 16 would probably be a better value. 221 */ 222#ifndef BROOKTREE_DEF_LATENCY_VALUE 223#define BROOKTREE_DEF_LATENCY_VALUE 0x10 224#endif 225 latency = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_LATENCY_TIMER); 226 latency = (latency >> 8) & 0xff; 227 228 if (!latency) { 229 if (bootverbose) { 230 printf("%s: PCI bus latency was 0 changing to %d", 231 bktr_name(bktr), BROOKTREE_DEF_LATENCY_VALUE); 232 } 233 latency = BROOKTREE_DEF_LATENCY_VALUE; 234 pci_conf_write(pa->pa_pc, pa->pa_tag, 235 PCI_LATENCY_TIMER, latency<<8); 236 } 237 238 239 /* read the pci id and determine the card type */ 240 fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG); 241 rev = PCI_REVISION(pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG)); 242 243 common_bktr_attach(bktr, unit, fun, rev); 244 245#if NRADIO > 0 246 if (bktr->card.tuner->pllControl[3] != 0x00) 247 radio_attach_mi(&bktr_hw_if, bktr, &bktr->bktr_dev); 248#endif 249} 250 251 252/* 253 * Special Memory Allocation 254 */ 255vaddr_t 256get_bktr_mem(bktr_ptr_t bktr, bus_dmamap_t *dmapp, unsigned int size) 257{ 258 bus_dma_tag_t dmat = bktr->dmat; 259 bus_dma_segment_t seg; 260 bus_size_t align; 261 int rseg; 262 caddr_t kva; 263 264 /* 265 * Allocate a DMA area 266 */ 267 align = 1 << 24; 268 if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1, 269 &rseg, BUS_DMA_NOWAIT)) { 270 align = PAGE_SIZE; 271 if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1, 272 &rseg, BUS_DMA_NOWAIT)) { 273 printf("%s: Unable to dmamem_alloc of %d bytes\n", 274 bktr_name(bktr), size); 275 return 0; 276 } 277 } 278 if (bus_dmamem_map(dmat, &seg, rseg, size, 279 &kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) { 280 printf("%s: Unable to dmamem_map of %d bytes\n", 281 bktr_name(bktr), size); 282 bus_dmamem_free(dmat, &seg, rseg); 283 return 0; 284 } 285 /* 286 * Create and locd the DMA map for the DMA area 287 */ 288 if (bus_dmamap_create(dmat, size, 1, size, 0, BUS_DMA_NOWAIT, dmapp)) { 289 printf("%s: Unable to dmamap_create of %d bytes\n", 290 bktr_name(bktr), size); 291 bus_dmamem_unmap(dmat, kva, size); 292 bus_dmamem_free(dmat, &seg, rseg); 293 return 0; 294 } 295 if (bus_dmamap_load(dmat, *dmapp, kva, size, NULL, BUS_DMA_NOWAIT)) { 296 printf("%s: Unable to dmamap_load of %d bytes\n", 297 bktr_name(bktr), size); 298 bus_dmamem_unmap(dmat, kva, size); 299 bus_dmamem_free(dmat, &seg, rseg); 300 bus_dmamap_destroy(dmat, *dmapp); 301 return 0; 302 } 303 return (vaddr_t)kva; 304} 305 306void 307free_bktr_mem(bktr_ptr_t bktr, bus_dmamap_t dmap, vaddr_t kva) 308{ 309 bus_dma_tag_t dmat = bktr->dmat; 310 311 bus_dmamem_unmap(dmat, (caddr_t)kva, dmap->dm_mapsize); 312 bus_dmamem_free(dmat, dmap->dm_segs, 1); 313 bus_dmamap_destroy(dmat, dmap); 314} 315 316 317/*--------------------------------------------------------- 318** 319** BrookTree 848 character device driver routines 320** 321**--------------------------------------------------------- 322*/ 323 324 325#define VIDEO_DEV 0x00 326#define TUNER_DEV 0x01 327#define VBI_DEV 0x02 328 329#define UNIT(x) ((minor((x)) < 16) ? minor((x)) : ((minor((x)) - 16) / 2)) 330#define FUNCTION(x) ((minor((x)) < 16) ? VIDEO_DEV : ((minor((x)) & 0x1) ? \ 331 VBI_DEV : TUNER_DEV)) 332 333/* 334 * 335 */ 336int 337bktr_open(dev_t dev, int flags, int fmt, struct proc *p) 338{ 339 bktr_ptr_t bktr; 340 int unit; 341 342 unit = UNIT(dev); 343 344 /* unit out of range */ 345 if ((unit >= bktr_cd.cd_ndevs) || (bktr_cd.cd_devs[unit] == NULL)) 346 return(ENXIO); 347 348 bktr = bktr_cd.cd_devs[unit]; 349 350 if (!(bktr->flags & METEOR_INITIALIZED)) /* device not found */ 351 return(ENXIO); 352 353 switch (FUNCTION(dev)) { 354 case VIDEO_DEV: 355 return(video_open(bktr)); 356 case TUNER_DEV: 357 return(tuner_open(bktr)); 358 case VBI_DEV: 359 return(vbi_open(bktr)); 360 } 361 362 return(ENXIO); 363} 364 365 366/* 367 * 368 */ 369int 370bktr_close(dev_t dev, int flags, int fmt, struct proc *p) 371{ 372 bktr_ptr_t bktr; 373 int unit; 374 375 unit = UNIT(dev); 376 377 bktr = bktr_cd.cd_devs[unit]; 378 379 switch (FUNCTION(dev)) { 380 case VIDEO_DEV: 381 return(video_close(bktr)); 382 case TUNER_DEV: 383 return(tuner_close(bktr)); 384 case VBI_DEV: 385 return(vbi_close(bktr)); 386 } 387 388 return(ENXIO); 389} 390 391/* 392 * 393 */ 394int 395bktr_read(dev_t dev, struct uio *uio, int ioflag) 396{ 397 bktr_ptr_t bktr; 398 int unit; 399 400 unit = UNIT(dev); 401 402 bktr = bktr_cd.cd_devs[unit]; 403 404 switch (FUNCTION(dev)) { 405 case VIDEO_DEV: 406 return(video_read(bktr, unit, dev, uio)); 407 case VBI_DEV: 408 return(vbi_read(bktr, uio, ioflag)); 409 } 410 411 return(ENXIO); 412} 413 414 415/* 416 * 417 */ 418int 419bktr_write(dev_t dev, struct uio *uio, int ioflag) 420{ 421 /* operation not supported */ 422 return(EOPNOTSUPP); 423} 424 425/* 426 * 427 */ 428int 429bktr_ioctl(dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct proc* pr) 430{ 431 bktr_ptr_t bktr; 432 int unit; 433 434 unit = UNIT(dev); 435 436 bktr = bktr_cd.cd_devs[unit]; 437 438 if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */ 439 return(ENOMEM); 440 441 switch (FUNCTION(dev)) { 442 case VIDEO_DEV: 443 return(video_ioctl(bktr, unit, cmd, arg, pr)); 444 case TUNER_DEV: 445 return(tuner_ioctl(bktr, unit, cmd, arg, pr)); 446 } 447 448 return(ENXIO); 449} 450 451/* 452 * 453 */ 454paddr_t 455bktr_mmap(dev_t dev, off_t offset, int nprot) 456{ 457 int unit; 458 bktr_ptr_t bktr; 459 460 unit = UNIT(dev); 461 462 if (FUNCTION(dev) > 0) /* only allow mmap on /dev/bktr[n] */ 463 return(-1); 464 465 bktr = bktr_cd.cd_devs[unit]; 466 467 if (offset < 0) 468 return(-1); 469 470 if (offset >= bktr->alloc_pages * PAGE_SIZE) 471 return(-1); 472 473 return (bus_dmamem_mmap(bktr->dmat, bktr->dm_mem->dm_segs, 1, 474 offset, nprot, BUS_DMA_WAITOK)); 475} 476 477#if NRADIO > 0 478int 479bktr_set_info(void *v, struct radio_info *ri) 480{ 481 struct bktr_softc *sc = v; 482 struct TVTUNER *tv = &sc->tuner; 483 u_int32_t freq; 484 u_int32_t chan; 485 486 if (ri->mute) { 487 /* mute the audio stream by switching the mux */ 488 set_audio(sc, AUDIO_MUTE); 489 } else { 490 /* unmute the audio stream */ 491 set_audio(sc, AUDIO_UNMUTE); 492 init_audio_devices(sc); 493 } 494 495 set_audio(sc, AUDIO_INTERN); /* use internal audio */ 496 temp_mute(sc, TRUE); 497 498 if (ri->tuner_mode == RADIO_TUNER_MODE_TV) { 499 if (ri->chan) { 500 if (ri->chan < MIN_TV_CHAN) 501 ri->chan = MIN_TV_CHAN; 502 if (ri->chan > MAX_TV_CHAN) 503 ri->chan = MAX_TV_CHAN; 504 505 chan = ri->chan; 506 ri->chan = tv_channel(sc, chan); 507 tv->tuner_mode = BT848_TUNER_MODE_TV; 508 } else { 509 ri->chan = tv->channel; 510 } 511 } else { 512 if (ri->freq) { 513 if (ri->freq < MIN_FM_FREQ) 514 ri->freq = MIN_FM_FREQ; 515 if (ri->freq > MAX_FM_FREQ) 516 ri->freq = MAX_FM_FREQ; 517 518 freq = ri->freq / 10; 519 ri->freq = tv_freq(sc, freq, FM_RADIO_FREQUENCY) * 10; 520 tv->tuner_mode = BT848_TUNER_MODE_RADIO; 521 } else { 522 ri->freq = tv->frequency; 523 } 524 } 525 526 if (ri->chnlset >= CHNLSET_MIN && ri->chnlset <= CHNLSET_MAX) 527 tv->chnlset = ri->chnlset; 528 else 529 tv->chnlset = DEFAULT_CHNLSET; 530 531 temp_mute(sc, FALSE); 532 533 return (0); 534} 535 536int 537bktr_get_info(void *v, struct radio_info *ri) 538{ 539 struct bktr_softc *sc = v; 540 struct TVTUNER *tv = &sc->tuner; 541 int status; 542 543 status = get_tuner_status(sc); 544 545#define STATUSBIT_STEREO 0x10 546 ri->mute = (int)sc->audio_mute_state ? 1 : 0; 547 ri->caps = RADIO_CAPS_DETECT_STEREO | RADIO_CAPS_HW_AFC; 548 ri->info = (status & STATUSBIT_STEREO) ? RADIO_INFO_STEREO : 0; 549 550 /* not yet supported */ 551 ri->volume = ri->rfreq = ri->lock = 0; 552 553 switch (tv->tuner_mode) { 554 case BT848_TUNER_MODE_TV: 555 ri->tuner_mode = RADIO_TUNER_MODE_TV; 556 ri->freq = tv->frequency * 1000 / 16; 557 break; 558 case BT848_TUNER_MODE_RADIO: 559 ri->tuner_mode = RADIO_TUNER_MODE_RADIO; 560 ri->freq = tv->frequency * 10; 561 break; 562 } 563 564 /* 565 * The field ri->stereo is used to forcible switch to 566 * mono/stereo, not as an indicator of received signal quality. 567 * The ri->info is for that purpose. 568 */ 569 ri->stereo = 1; /* Can't switch to mono, always stereo */ 570 571 ri->chan = tv->channel; 572 ri->chnlset = tv->chnlset; 573 574 return (0); 575} 576#endif /* NRADIO */ 577