123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202 |
- /*
- * Driver for Bt848 TV tuner.
- *
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- #include "io.h"
- #include "hcwAMC.h"
- #define max(a, b) (((a) > (b))? (a): (b))
- enum {
- Qdir = 0,
- Qsubdir,
- Qsubbase,
- Qvdata = Qsubbase,
- Qadata,
- Qctl,
- Qregs,
- Brooktree_vid = 0x109e,
- Brooktree_848_did = 0x0350,
- Brooktree_878_did = 0x036E,
- Intel_vid = 0x8086,
- Intel_82437_did = 0x122d,
- K = 1024,
- M = K * K,
- Ntvs = 4,
- Numring = 16,
- ntsc_rawpixels = 910,
- ntsc_sqpixels = 780, // Including blanking & inactive
- ntsc_hactive = 640,
- ntsc_vactive = 480,
- ntsc_clkx1delay = 135, // Clock ticks.
- ntsc_clkx1hactive = 754,
- ntsc_vdelay = 26, // # of scan lines.
- ntsc_vscale = 0,
- i2c_nostop = 1 << 5,
- i2c_nos1b = 1 << 4,
- i2c_timing = 7 << 4,
- i2c_bt848w3b = 1 << 2,
- i2c_bt848scl = 1 << 1,
- i2c_bt848sda = 1 << 0,
- i2c_scl = i2c_bt848scl,
- i2c_sda = i2c_bt848sda,
- i2c_miroproee = 0x80, // MIRO PRO EEPROM
- i2c_tea6300 = 0x80,
- i2c_tda8425 = 0x82,
- i2c_tda9840 = 0x84,
- i2c_tda9850 = 0xb6,
- i2c_haupee = 0xa0, // Hauppage EEPROM
- i2c_stbee = 0xae, // STB EEPROM
- i2c_msp3400 = 0x80,
- i2c_timeout = 1000,
- i2c_delay = 10,
- Bt848_miropro = 0,
- Bt848_miro,
- Bt878_hauppauge,
- // Bit fields.
- iform_muxsel1 = 3 << 5, // 004
- iform_muxsel0 = 2 << 5,
- iform_xtselmask = 3 << 3,
- iform_xtauto = 3 << 3,
- iform_formatmask = 7 << 0,
- iform_ntsc = 1 << 0,
- control_ldec = 1 << 5, // 02C
- contrast_100percent = 0xd8, // 030
- vscale_interlaced = 1 << 5, // 04C
- adelay_ntsc = 104, // 060
- bdelay_ntsc = 93, // 064
- adc_crush = 1 << 0, // 068
- colorfmt_rgb16 = (2 << 4) | (2 << 0), // 0D4
- colorfmt_YCbCr422 = (8 << 4) | (8 << 0),
- colorfmt_YCbCr411 = (9 << 4) | (9 << 0),
- colorctl_gamma = 1 << 4, // 0D8
- capctl_fullframe = 1 << 4, // 0DC
- capctl_captureodd = 1 << 1,
- capctl_captureeven = 1 << 0,
- vbipacksize = 0x190, // 0E0
- intstat_riscstatshift = 28, // 100
- intstat_i2crack = 1 << 25,
- intstat_scerr = 1 << 19,
- intstat_ocerr = 1 << 18,
- intstat_pabort = 1 << 17,
- intstat_riperr = 1 << 16,
- intstat_pperr = 1 << 15,
- intstat_fdsr = 1 << 14,
- intstat_ftrgt = 1 << 13,
- intstat_fbus = 1 << 12,
- intstat_risci = 1 << 11,
- intstat_i2cdone = 1 << 8,
- intstat_vpress = 1 << 5,
- intstat_hlock = 1 << 4,
- intstat_vsync = 1 << 1,
- intstat_fmtchg = 1 << 0,
- intmask_etbf = 1 << 23, // 104
- gpiodmactl_apwrdn = 1 << 26, // 10C
- gpiodmactl_daes2 = 1 << 13,
- gpiodmactl_daiomda = 1 << 6,
- gpiodmactl_pltp23_16 = 2 << 6,
- gpiodmactl_pltp23_0 = 0 << 6,
- gpiodmactl_pltp1_16 = 2 << 4,
- gpiodmactl_pltp1_0 = 0 << 4,
- gpiodmactl_acapenable = 1 << 4,
- gpiodmactl_pktp_32 = 3 << 2,
- gpiodmactl_pktp_0 = 0 << 2,
- gpiodmactl_riscenable = 1 << 1,
- gpiodmactl_fifoenable = 1 << 0,
- // RISC instructions and parameters.
- fifo_vre = 0x4,
- fifo_vro = 0xc,
- fifo_fm1 = 0x6,
- fifo_fm3 = 0xe,
- riscirq = 1 << 24,
- riscwrite = 1 << 28,
- riscwrite123 = 9 << 28,
- riscwrite1s23 = 11 << 28,
- riscwrite_sol = 1 << 27,
- riscwrite_eol = 1 << 26,
- riscskip = 0x2 << 28,
- riscjmp = 0x7 << 28,
- riscsync = 0x8 << 28,
- riscsync_resync = 1 << 15,
- riscsync_vre = fifo_vre << 0,
- riscsync_vro = fifo_vro << 0,
- riscsync_fm1 = fifo_fm1 << 0,
- riscsync_fm3 = fifo_fm3 << 0,
- risclabelshift_set = 16,
- risclabelshift_reset = 20,
- AudioTuner = 0,
- AudioRadio,
- AudioExtern,
- AudioIntern,
- AudioOff,
- AudioOn,
-
- asel_tv = 0,
- asel_radio,
- asel_mic,
- asel_smxc,
- Hwbase_ad = 448000,
- msp_dem = 0x10,
- msp_bbp = 0x12,
- // Altera definitions.
- gpio_altera_data = 1 << 0,
- gpio_altera_clock = 1 << 20,
- gpio_altera_nconfig = 1 << 23,
- Ial = 0x140001,
- Idma = 0x100002,
- Adsp = 0x7fd8,
- Adsp_verifysystem = 1,
- Adsp_querysupportplay,
- Adsp_setstyle,
- Adsp_setsrate,
- Adsp_setchannels,
- Adsp_setresolution,
- Adsp_setcrcoptions,
- Adsp_bufenqfor,
- Adsp_logbuffer,
- Adsp_startplay,
- Adsp_stopplay,
- Adsp_autostop,
- Adsp_startrecord,
- Adsp_stoprecord,
- Adsp_getlastprocessed,
- Adsp_pause,
- Adsp_resume,
- Adsp_setvolume,
- Adsp_querysupportrecord,
- Adsp_generalbufenq,
- Adsp_setdownmixtype,
- Adsp_setigain,
- Adsp_setlineout,
- Adsp_setlangmixtype,
- Kfir_gc = 0,
- Kfir_dsp_riscmc,
- Kfir_dsp_risccram,
- Kfir_dsp_unitmc,
- Kfir_bsm_mc,
- Kfir_mux_mc,
- Kfir_devid_gc = 7,
- Kfir_devid_dsp = 4,
- Kfir_devid_bsm = 5,
- Kfir_devid_mux = 8,
- Kfir_200 = 200,
- Kfir_dev_inst = Kfir_200,
- Kfir_201 = 201,
- Kfir_exec = Kfir_201,
- Kfir_202 = 202,
- Kfir_adr_eready = 254,
- Kfir_d_eready_encoding = 0,
- Kfir_d_eready_ready,
- Kfir_d_eready_test,
- Kfir_d_eready_stopdetect,
- Kfir_d_eready_seqend,
- VT_KFIR_OFF = 0,
- VT_KFIR_ON,
- VT_KFIR_LAYER_II = 1,
- VT_KFIR_STEREO = 1,
- Gpioinit = 0,
- Gpiooutput,
- Gpioinput,
- Srate_5512 = 0,
- Srate_11025 = 2,
- Srate_16000 = 3,
- Srate_22050 = 4,
- Srate_32000 = 5,
- Srate_44100 = 6,
- Srate_48000 = 7,
- };
- typedef struct Variant Variant;
- struct Variant {
- ushort vid;
- ushort did;
- char *name;
- };
- typedef struct Bt848 Bt848;
- struct Bt848 {
- ulong devstat; // 000
- ulong iform; // 004
- ulong tdec; // 008
- ulong ecrop; // 00C
- ulong evdelaylo; // 010
- ulong evactivelo; // 014
- ulong ehdelaylo; // 018
- ulong ehactivelo; // 01C
- ulong ehscalehi; // 020
- ulong ehscalelo; // 024
- ulong bright; // 028
- ulong econtrol; // 02C
- ulong contrastlo; // 030
- ulong satulo; // 034
- ulong satvlo; // 038
- ulong hue; // 03C
- ulong escloop; // 040
- ulong pad0; // 044
- ulong oform; // 048
- ulong evscalehi; // 04C
- ulong evscalelo; // 050
- ulong test; // 054
- ulong pad1[2]; // 058-05C
- ulong adelay; // 060
- ulong bdelay; // 064
- ulong adc; // 068
- ulong evtc; // 06C
- ulong pad2[3]; // 070-078
- ulong sreset; // 07C
- ulong tglb; // 080
- ulong tgctrl; // 084
- ulong pad3; // 088
- ulong ocrop; // 08C
- ulong ovdelaylo; // 090
- ulong ovactivelo; // 094
- ulong ohdelaylo; // 098
- ulong ohactivelo; // 09C
- ulong ohscalehi; // 0A0
- ulong ohscalelo; // 0A4
- ulong pad4; // 0A8
- ulong ocontrol; // 0AC
- ulong pad5[4]; // 0B0-0BC
- ulong oscloop; // 0C0
- ulong pad6[2]; // 0C4-0C8
- ulong ovscalehi; // 0CC
- ulong ovscalelo; // 0D0
- ulong colorfmt; // 0D4
- ulong colorctl; // 0D8
- ulong capctl; // 0DC
- ulong vbipacksize; // 0E0
- ulong vbipackdel; // 0E4
- ulong fcap; // 0E8
- ulong ovtc; // 0EC
- ulong pllflo; // 0F0
- ulong pllfhi; // 0F4
- ulong pllxci; // 0F8
- ulong dvsif; // 0FC
- ulong intstat; // 100
- ulong intmask; // 104
- ulong pad7; // 108
- ulong gpiodmactl; // 10C
- ulong i2c; // 110
- ulong riscstrtadd; // 114
- ulong gpioouten; // 118
- ulong gpioreginp; // 11C
- ulong risccount; // 120
- ulong pad8[55]; // 124-1FC
- ulong gpiodata[64]; // 200-2FC
- };
- #define packetlen i2c
- typedef struct Tuner Tuner;
- struct Tuner {
- char *name;
- ushort freq_vhfh; // Start frequency
- ushort freq_uhf;
- uchar VHF_L;
- uchar VHF_H;
- uchar UHF;
- uchar cfg;
- ushort offs;
- };
- typedef struct Frame Frame;
- struct Frame {
- ulong *fstart;
- ulong *fjmp;
- uchar *fbase;
- };
- typedef struct Tv Tv;
- struct Tv {
- Lock;
- Rendez;
- Bt848 *bt848;
- Bt848 *bt878; // Really only audio control registers
- Variant *variant;
- Tuner *tuner;
- Pcidev *pci;
- uchar i2ctuneraddr;
- uchar i2ccmd; // I2C command
- int board; // What board is this?
- ulong cfmt; // Current color format.
- int channel; // Current channel
- Ref fref; // Copying images?
- int nframes; // Number of frames to capture.
- Frame *frames; // DMA program
- int lvframe; // Last video frame DMAed
- uchar *amux; // Audio multiplexer.
- int nablocks; // Number of audio blocks allocated
- int absize; // Audio block size
- int narblocks; // Number of audio blocks received
- ulong *arisc; // Audio risc bloc
- uchar *abuf; // Audio data buffers
- char ainfo[128];
- // WinTV/PVR stuff.
- int msp;
- Lock kfirlock;
- ulong i2cstate; // Last i2c state.
- int gpiostate; // Current GPIO state
- ulong alterareg; // Last used altera register
- ulong alteraclock; // Used to clock the altera
- int asrate; // Audio sample rate
- uchar aleft, aright; // Left and right audio volume
- ulong kfirclock;
- Ref aref; // Copying audio?
- };
- enum {
- TemicPAL = 0,
- PhilipsPAL,
- PhilipsNTSC,
- PhilipsSECAM,
- Notuner,
- PhilipsPALI,
- TemicNTSC,
- TemicPALI,
- Temic4036,
- AlpsTSBH1,
- AlpsTSBE1,
- Freqmultiplier = 16,
- };
- static Tuner tuners[] = {
- {"Temic PAL", Freqmultiplier * 140.25, Freqmultiplier * 463.25,
- 0x02, 0x04, 0x01, 0x8e, 623 },
- {"Philips PAL_I", Freqmultiplier * 140.25, Freqmultiplier * 463.25,
- 0xa0, 0x90, 0x30, 0x8e, 623 },
- {"Philips NTSC", Freqmultiplier * 157.25, Freqmultiplier * 451.25,
- 0xA0, 0x90, 0x30, 0x8e, 732 },
- {"Philips SECAM", Freqmultiplier * 168.25, Freqmultiplier * 447.25,
- 0xA7, 0x97, 0x37, 0x8e, 623 },
- {"NoTuner", 0, 0,
- 0x00, 0x00, 0x00, 0x00, 0 },
- {"Philips PAL", Freqmultiplier * 168.25, Freqmultiplier * 447.25,
- 0xA0, 0x90, 0x30, 0x8e, 623 },
- {"Temic NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25,
- 0x02, 0x04, 0x01, 0x8e, 732 },
- {"TEMIC PAL_I", Freqmultiplier * 170.00, Freqmultiplier * 450.00,
- 0x02, 0x04, 0x01, 0x8e, 623 },
- {"Temic 4036 FY5 NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25,
- 0xa0, 0x90, 0x30, 0x8e, 732 },
- {"Alps TSBH1", Freqmultiplier * 137.25, Freqmultiplier * 385.25,
- 0x01, 0x02, 0x08, 0x8e, 732 },
- {"Alps TSBE1", Freqmultiplier * 137.25, Freqmultiplier * 385.25,
- 0x01, 0x02, 0x08, 0x8e, 732 },
- };
- static int hp_tuners[] = {
- Notuner,
- Notuner,
- Notuner,
- Notuner,
- Notuner,
- PhilipsNTSC,
- Notuner,
- Notuner,
- PhilipsPAL,
- PhilipsSECAM,
- PhilipsNTSC,
- PhilipsPALI,
- Notuner,
- Notuner,
- TemicPAL,
- TemicPALI,
- Notuner,
- PhilipsSECAM,
- PhilipsNTSC,
- PhilipsPALI,
- Notuner,
- PhilipsPAL,
- Notuner,
- PhilipsNTSC,
- };
- enum {
- CMvstart,
- CMastart,
- CMastop,
- CMvgastart,
- CMvstop,
- CMchannel,
- CMcolormode,
- CMvolume,
- CMmute,
- };
- static Cmdtab tvctlmsg[] = {
- CMvstart, "vstart", 2,
- CMastart, "astart", 5,
- CMastop, "astop", 1,
- CMvgastart, "vgastart", 3,
- CMvstop, "vstop", 1,
- CMchannel, "channel", 3,
- CMcolormode, "colormode", 2,
- CMvolume, "volume", 3,
- CMmute, "mute", 1,
- };
- static Variant variant[] = {
- { Brooktree_vid, Brooktree_848_did, "Brooktree 848 TV tuner", },
- { Brooktree_vid, Brooktree_878_did, "Brooktree 878 TV tuner", },
- };
- static char *boards[] = {
- "MIRO PRO",
- "MIRO",
- "Hauppauge Bt878",
- };
- static ushort Adspfsample[] = {
- 0x500, 0x700, 0x400, 0x600, 0x300, 0x200, 0x000, 0x100
- };
- static ushort Adspstereorates[] = {
- 64, 96, 112, 128, 160, 192, 224, 256, 320, 384
- };
- static uchar miroamux[] = { 2, 0, 0, 0, 10, 0 };
- static uchar hauppaugeamux[] = { 0, 1, 2, 3, 4, 0 };
- static char *nicamstate[] = {
- "analog", "???", "digital", "bad digital receiption"
- };
- static Tv tvs[Ntvs];
- static int ntvs;
- static int i2cread(Tv *, uchar, uchar *);
- static int i2cwrite(Tv *, uchar, uchar, uchar, int);
- static void tvinterrupt(Ureg *, Tv *);
- static void vgastart(Tv *, ulong, int);
- static void vstart(Tv *, int, int, int, int);
- static void astart(Tv *, char *, uint, uint, uint);
- static void vstop(Tv *);
- static void astop(Tv *);
- static void colormode(Tv *, char *);
- static void frequency(Tv *, int, int);
- static int getbitspp(Tv *);
- static char *getcolormode(ulong);
- static int mspreset(Tv *);
- static void i2cscan(Tv *);
- static int kfirinitialize(Tv *);
- static void msptune(Tv *);
- static void mspvolume(Tv *, int, int, int);
- static void gpioenable(Tv *, ulong, ulong);
- static void gpiowrite(Tv *, ulong, ulong);
- static void
- tvinit(void)
- {
- Pcidev *pci;
- ulong intmask;
- // Test for a triton memory controller.
- intmask = 0;
- if (pcimatch(nil, Intel_vid, Intel_82437_did))
- intmask = intmask_etbf;
- pci = nil;
- while ((pci = pcimatch(pci, 0, 0)) != nil) {
- int i, t;
- Tv *tv;
- Bt848 *bt848;
- ushort hscale, hdelay;
- uchar v;
- for (i = 0; i != nelem(variant); i++)
- if (pci->vid == variant[i].vid && pci->did == variant[i].did)
- break;
- if (i == nelem(variant))
- continue;
- if (ntvs >= Ntvs) {
- print("#V: Too many TV cards found\n");
- continue;
- }
- tv = &tvs[ntvs++];
- tv->variant = &variant[i];
- tv->pci = pci;
- tv->bt848 = (Bt848 *)upamalloc(pci->mem[0].bar & ~0x0F, 4 * K, K);
- if (tv->bt848 == nil)
- panic("#V: Cannot allocate memory for Bt848");
- bt848 = tv->bt848;
- // i2c stuff.
- if (pci->did >= 878)
- tv->i2ccmd = 0x83;
- else
- tv->i2ccmd = i2c_timing | i2c_bt848scl | i2c_bt848sda;
- t = 0;
- if (i2cread(tv, i2c_haupee, &v)) {
- uchar ee[256];
- Pcidev *pci878;
- Bt848 *bt878;
- tv->board = Bt878_hauppauge;
- if (!i2cwrite(tv, i2c_haupee, 0, 0, 0))
- panic("#V: Cannot write to Hauppauge EEPROM");
- for (i = 0; i != sizeof ee; i++)
- if (!i2cread(tv, i2c_haupee + 1, &ee[i]))
- panic("#V: Cannot read from Hauppauge EEPROM");
- if (ee[9] > sizeof hp_tuners / sizeof hp_tuners[0])
- panic("#V: Tuner out of range (max %d, this %d)",
- sizeof hp_tuners / sizeof hp_tuners[0], ee[9]);
- t = hp_tuners[ee[9]];
- // Initialize the audio channel.
- if ((pci878 = pcimatch(nil, Brooktree_vid, 0x878)) == nil)
- panic("#V: Unsupported Hauppage board");
- tv->bt878 = bt878 =
- (Bt848 *)upamalloc(pci878->mem[0].bar & ~0x0F, 4 * K, K);
- if (bt878 == nil)
- panic("#V: Cannot allocate memory for the Bt878");
- kfirinitialize(tv);
- // i2cscan(tv);
- mspreset(tv);
- bt878->gpiodmactl = 0;
- bt878->intstat = (ulong)-1;
- intrenable(pci878->intl, (void (*)(Ureg *, void *))tvinterrupt,
- tv, pci878->tbdf, "tv");
- tv->amux = hauppaugeamux;
- }
- else if (i2cread(tv, i2c_stbee, &v)) {
- USED(t);
- panic("#V: Cannot deal with STB cards\n");
- }
- else if (i2cread(tv, i2c_miroproee, &v)) {
- tv->board = Bt848_miropro;
- t = ((bt848->gpiodata[0] >> 10) - 1) & 7;
- tv->amux = miroamux;
- }
- else {
- tv->board = Bt848_miro;
- tv->amux = miroamux;
- t = ((bt848->gpiodata[0] >> 10) - 1) & 7;
- }
- if (t >= nelem(tuners))
- t = 4;
- tv->tuner = &tuners[t];
- tv->i2ctuneraddr =
- i2cread(tv, 0xc1, &v)? 0xc0:
- i2cread(tv, 0xc3, &v)? 0xc2:
- i2cread(tv, 0xc5, &v)? 0xc4:
- i2cread(tv, 0xc7, &v)? 0xc6: -1;
- bt848->capctl = capctl_fullframe;
- bt848->adelay = adelay_ntsc;
- bt848->bdelay = bdelay_ntsc;
- bt848->iform = iform_muxsel0|iform_xtauto|iform_ntsc;
- bt848->vbipacksize = vbipacksize & 0xff;
- bt848->vbipackdel = (vbipacksize >> 8) & 1;
- // setpll(bt848);
- tv->cfmt = bt848->colorfmt = colorfmt_rgb16;
- hscale = (ntsc_rawpixels * 4096) / ntsc_sqpixels - 4096;
- hdelay = (ntsc_clkx1delay * ntsc_hactive) / ntsc_clkx1hactive;
- bt848->ovtc = bt848->evtc = 0;
- bt848->ehscalehi = bt848->ohscalehi = (hscale >> 8) & 0xff;
- bt848->ehscalelo = bt848->ohscalelo = hscale & 0xff;
- bt848->evscalehi &= ~0x1f;
- bt848->ovscalehi &= ~0x1f;
- bt848->evscalehi |= vscale_interlaced | ((ntsc_vscale >> 8) & 0x1f);
- bt848->ovscalehi |= vscale_interlaced | (ntsc_vscale >> 8) & 0x1f;
- bt848->evscalelo = bt848->ovscalelo = ntsc_vscale & 0xff;
- bt848->ehactivelo = bt848->ohactivelo = ntsc_hactive & 0xff;
- bt848->ehdelaylo = bt848->ohdelaylo = hdelay & 0xff;
- bt848->evactivelo = bt848->ovactivelo = ntsc_vactive & 0xff;
- bt848->evdelaylo = bt848->ovdelaylo = ntsc_vdelay & 0xff;
- bt848->ecrop = bt848->ocrop =
- ((ntsc_hactive >> 8) & 0x03) |
- ((hdelay >> 6) & 0x0C) |
- ((ntsc_vactive >> 4) & 0x30) |
- ((ntsc_vdelay >> 2) & 0xC0);
- bt848->colorctl = colorctl_gamma;
- bt848->capctl = 0;
- bt848->gpiodmactl = gpiodmactl_pltp23_16 |
- gpiodmactl_pltp1_16 | gpiodmactl_pktp_32;
- bt848->gpioreginp = 0;
- bt848->contrastlo = contrast_100percent;
- bt848->bright = 16;
- bt848->adc = (2 << 6) | adc_crush;
- bt848->econtrol = bt848->ocontrol = control_ldec;
- bt848->escloop = bt848->oscloop = 0;
- bt848->intstat = (ulong)-1;
- bt848->intmask = intmask |
- intstat_vsync | intstat_scerr | intstat_risci | intstat_ocerr |
- intstat_vpress | intstat_fmtchg;
- if (tv->amux) {
- gpioenable(tv, ~0xfff, 0xfff);
- gpiowrite(tv, ~0xfff, tv->amux[AudioRadio]);
- }
- print("#V%ld: %s (rev %d) (%s/%s) intl %d\n",
- tv - tvs, tv->variant->name, pci->rid, boards[tv->board],
- tv->tuner->name, pci->intl);
- intrenable(pci->intl, (void (*)(Ureg *, void *))tvinterrupt,
- tv, pci->tbdf, "tv");
- }
- }
- static Chan*
- tvattach(char *spec)
- {
- return devattach('V', spec);
- }
- #define TYPE(q) ((int)((q).path & 0xff))
- #define DEV(q) ((int)(((q).path >> 8) & 0xff))
- #define QID(d, t) ((((d) & 0xff) << 8) | (t))
- static int
- tv1gen(Chan *c, int i, Dir *dp)
- {
- Qid qid;
- switch (i) {
- case Qvdata:
- mkqid(&qid, QID(DEV(c->qid), Qvdata), 0, QTFILE);
- devdir(c, qid, "video", 0, eve, 0444, dp);
- return 1;
- case Qadata:
- mkqid(&qid, QID(DEV(c->qid), Qadata), 0, QTFILE);
- devdir(c, qid, "audio", 0, eve, 0444, dp);
- return 1;
- case Qctl:
- mkqid(&qid, QID(DEV(c->qid), Qctl), 0, QTFILE);
- devdir(c, qid, "ctl", 0, eve, 0444, dp);
- return 1;
- case Qregs:
- mkqid(&qid, QID(DEV(c->qid), Qregs), 0, QTFILE);
- devdir(c, qid, "regs", 0, eve, 0444, dp);
- return 1;
- }
- return -1;
- }
- static int
- tvgen(Chan *c, char *, Dirtab *, int, int i, Dir *dp)
- {
- Qid qid;
- int dev;
- dev = DEV(c->qid);
- switch (TYPE(c->qid)) {
- case Qdir:
- if (i == DEVDOTDOT) {
- mkqid(&qid, Qdir, 0, QTDIR);
- devdir(c, qid, "#V", 0, eve, 0555, dp);
- return 1;
- }
- if (i >= ntvs)
- return -1;
-
- mkqid(&qid, QID(i, Qsubdir), 0, QTDIR);
- snprint(up->genbuf, sizeof(up->genbuf), "tv%d", i);
- devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
- return 1;
- case Qsubdir:
- if (i == DEVDOTDOT) {
- mkqid(&qid, QID(dev, Qdir), 0, QTDIR);
- snprint(up->genbuf, sizeof(up->genbuf), "tv%d", dev);
- devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
- return 1;
- }
-
- return tv1gen(c, i + Qsubbase, dp);
-
- case Qvdata:
- case Qadata:
- case Qctl:
- case Qregs:
- return tv1gen(c, TYPE(c->qid), dp);
- default:
- return -1;
- }
- }
- static Walkqid *
- tvwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name, nname, 0, 0, tvgen);
- }
- static int
- tvstat(Chan *c, uchar *db, int n)
- {
- return devstat(c, db, n, 0, 0, tvgen);
- }
- static Chan*
- tvopen(Chan *c, int omode)
- {
- if (omode != OREAD &&
- TYPE(c->qid) != Qctl && TYPE(c->qid) != Qvdata)
- error(Eperm);
- switch (TYPE(c->qid)) {
- case Qdir:
- return devopen(c, omode, nil, 0, tvgen);
- case Qadata:
- if (tvs[DEV(c->qid)].bt878 == nil)
- error(Enonexist);
- break;
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- if (TYPE(c->qid) == Qadata)
- c->session = (Session *)0;
- return c;
- }
- static void
- tvclose(Chan *)
- {}
- static int
- audioblock(void *)
- {
- return 1;
- }
-
- static long
- tvread(Chan *c, void *a, long n, vlong offset)
- {
- static char regs[10 * K];
- static int regslen;
- Tv *tv;
- char *e, *p;
- uchar *src;
- USED(offset);
- switch(TYPE(c->qid)) {
- case Qdir:
- case Qsubdir:
- return devdirread(c, a, n, 0, 0, tvgen);
- case Qvdata: {
- int bpf, nb;
- tv = &tvs[DEV(c->qid)];
- bpf = ntsc_hactive * ntsc_vactive * getbitspp(tv) / 8;
- if (offset >= bpf)
- return 0;
- nb = n;
- if (offset + nb > bpf)
- nb = bpf - offset;
- ilock(tv);
- if (tv->frames == nil || tv->lvframe >= tv->nframes ||
- tv->frames[tv->lvframe].fbase == nil) {
- iunlock(tv);
- return 0;
- }
- src = tv->frames[tv->lvframe].fbase;
- incref(&tv->fref);
- iunlock(tv);
- memmove(a, src + offset, nb);
- decref(&tv->fref);
- return nb;
- }
- case Qadata: {
- ulong uablock = (ulong)c->session, bnum, tvablock;
- int boffs, nbytes;
- tv = &tvs[DEV(c->qid)];
- if (tv->bt878 == nil)
- error("#V: No audio device");
- if (tv->absize == 0)
- error("#V: audio not initialized");
- bnum = offset / tv->absize;
- boffs = offset % tv->absize;
- nbytes = tv->absize - boffs;
- incref(&tv->aref);
- while (1) {
- tvablock = tv->narblocks; // Current tv block.
- if (uablock == 0)
- uablock = tvablock - 1;
- if (tvablock >= uablock + bnum + tv->narblocks)
- uablock = tvablock - 1 - bnum;
- if (uablock + bnum == tvablock) {
- sleep(tv, audioblock, nil);
- continue;
- }
- break;
- }
- print("uablock %ld, bnum %ld, boffs %d, nbytes %d, tvablock %ld\n",
- uablock, bnum, boffs, nbytes, tvablock);
- src = tv->abuf + ((uablock + bnum) % tv->nablocks) * tv->absize;
- print("copying from %.8ulX (abuf %.8ulX), nbytes %d (block %ld.%ld)\n",
- src + boffs, tv->abuf, nbytes, uablock, bnum);
- memmove(a, src + boffs, nbytes);
- decref(&tv->aref);
-
- uablock += (boffs + nbytes) % tv->absize;
- c->session = (Session *)uablock;
- return nbytes;
- }
- case Qctl: {
- char str[128];
- tv = &tvs[DEV(c->qid)];
- snprint(str, sizeof str, "%dx%dx%d %s channel %d %s\n",
- ntsc_hactive, ntsc_vactive, getbitspp(tv),
- getcolormode(tv->cfmt), tv->channel,
- tv->ainfo);
- return readstr(offset, a, strlen(str) + 1, str);
- }
-
- case Qregs:
- if (offset == 0) {
- Bt848 *bt848;
- int i;
- tv = &tvs[DEV(c->qid)];
- bt848 = tv->bt848;
- e = regs + sizeof(regs);
- p = regs;
- for (i = 0; i < 0x300 >> 2; i++)
- p = seprint(p, e, "%.3X %.8ulX\n", i << 2, ((ulong *)bt848)[i]);
- if (tv->bt878) {
- bt848 = tv->bt878;
- for (i = 0; i < 0x300 >> 2; i++)
- p = seprint(p, e, "%.3X %.8ulX\n",
- i << 2, ((ulong *)bt848)[i]);
- }
-
- regslen = p - regs;
- }
- if (offset >= regslen)
- return 0;
- if (offset + n > regslen)
- n = regslen - offset;
- return readstr(offset, a, n, ®s[offset]);
- default:
- n = 0;
- break;
- }
- return n;
- }
- static long
- tvwrite(Chan *c, void *a, long n, vlong)
- {
- Cmdbuf *cb;
- Cmdtab *ct;
- Tv *tv;
- tv = &tvs[DEV(c->qid)];
- switch(TYPE(c->qid)) {
- case Qctl:
- cb = parsecmd(a, n);
- if(waserror()){
- free(cb);
- nexterror();
- }
- ct = lookupcmd(cb, tvctlmsg, nelem(tvctlmsg));
- switch (ct->index) {
- case CMvstart:
- vstart(tv, (int)strtol(cb->f[1], (char **)nil, 0),
- ntsc_hactive, ntsc_vactive, ntsc_hactive);
- break;
- case CMastart:
- astart(tv, cb->f[1], (uint)strtol(cb->f[2], (char **)nil, 0),
- (uint)strtol(cb->f[3], (char **)nil, 0),
- (uint)strtol(cb->f[4], (char **)nil, 0));
- break;
- case CMastop:
- astop(tv);
- break;
- case CMvgastart:
- vgastart(tv, strtoul(cb->f[1], (char **)nil, 0),
- (int)strtoul(cb->f[2], (char **)nil, 0));
- break;
- case CMvstop:
- vstop(tv);
- break;
- case CMchannel:
- frequency(tv, (int)strtol(cb->f[1], (char **)nil, 0),
- (int)strtol(cb->f[2], (char **)nil, 0));
- break;
- case CMcolormode:
- colormode(tv, cb->f[1]);
- break;
- case CMvolume:
- if (!tv->msp)
- error("#V: No volume control");
- mspvolume(tv, 0, (int)strtol(cb->f[1], (char **)nil, 0),
- (int)strtol(cb->f[2], (char **)nil, 0));
- break;
- case CMmute:
- if (!tv->msp)
- error("#V: No volume control");
- mspvolume(tv, 1, 0, 0);
- break;
- }
- poperror();
- free(cb);
- break;
- default:
- error(Eio);
- }
- return n;
- }
- Dev tvdevtab = {
- 'V',
- "tv",
- devreset,
- tvinit,
- devshutdown,
- tvattach,
- tvwalk,
- tvstat,
- tvopen,
- devcreate,
- tvclose,
- tvread,
- devbread,
- tvwrite,
- devbwrite,
- devremove,
- devwstat,
- };
- static void
- tvinterrupt(Ureg *, Tv *tv)
- {
- Bt848 *bt848 = tv->bt848,
- *bt878 = tv->bt878;
- while (1) {
- ulong vstat, astat;
- uchar fnum;
- vstat = bt848->intstat;
- fnum = (vstat >> intstat_riscstatshift) & 0xf;
- vstat &= bt848->intmask;
- if (bt878)
- astat = bt878->intstat & bt878->intmask;
- else
- astat = 0;
- if (vstat == 0 && astat == 0)
- break;
- if (astat)
- print("vstat %.8luX, astat %.8luX\n", vstat, astat);
- bt848->intstat = vstat;
- if (bt878)
- bt878->intstat = astat;
- if ((vstat & intstat_fmtchg) == intstat_fmtchg) {
- iprint("int: fmtchg\n");
- vstat &= ~intstat_fmtchg;
- }
- if ((vstat & intstat_vpress) == intstat_vpress) {
- // iprint("int: vpress\n");
- vstat &= ~intstat_vpress;
- }
-
- if ((vstat & intstat_vsync) == intstat_vsync) {
- vstat &= ~intstat_vsync;
- }
- if ((vstat & intstat_scerr) == intstat_scerr) {
- iprint("int: scerr\n");
- bt848->gpiodmactl &=
- ~(gpiodmactl_riscenable|gpiodmactl_fifoenable);
- bt848->gpiodmactl |= gpiodmactl_fifoenable;
- bt848->gpiodmactl |= gpiodmactl_riscenable;
- vstat &= ~intstat_scerr;
- }
- if ((vstat & intstat_risci) == intstat_risci) {
- tv->lvframe = fnum;
- vstat &= ~intstat_risci;
- }
-
- if ((vstat & intstat_ocerr) == intstat_ocerr) {
- iprint("int: ocerr\n");
- vstat &= ~intstat_ocerr;
- }
- if ((vstat & intstat_fbus) == intstat_fbus) {
- iprint("int: fbus\n");
- vstat &= ~intstat_fbus;
- }
- if (vstat)
- iprint("int: (v) ignored interrupts %.8ulX\n", vstat);
- if ((astat & intstat_risci) == intstat_risci) {
- tv->narblocks++;
- if ((tv->narblocks % 100) == 0)
- print("a");
- wakeup(tv);
- astat &= ~intstat_risci;
- }
- if ((astat & intstat_fdsr) == intstat_fdsr) {
- iprint("int: (a) fdsr\n");
- bt848->gpiodmactl &=
- ~(gpiodmactl_acapenable |
- gpiodmactl_riscenable | gpiodmactl_fifoenable);
- astat &= ~intstat_fdsr;
- }
-
- if (astat)
- iprint("int: (a) ignored interrupts %.8ulX\n", astat);
- }
- }
- static int
- i2cread(Tv *tv, uchar off, uchar *v)
- {
- Bt848 *bt848 = tv->bt848;
- ulong intstat;
- int i;
- bt848->intstat = intstat_i2cdone;
- bt848->i2c = (off << 24) | tv->i2ccmd;
- intstat = -1;
- for (i = 0; i != 1000; i++) {
- if ((intstat = bt848->intstat) & intstat_i2cdone)
- break;
- microdelay(1000);
- }
- if (i == 1000) {
- print("i2cread: timeout\n");
- return 0;
- }
- if ((intstat & intstat_i2crack) == 0)
- return 0;
- *v = bt848->i2c >> 8;
- return 1;
- }
- static int
- i2cwrite(Tv *tv, uchar addr, uchar sub, uchar data, int both)
- {
- Bt848 *bt848 = tv->bt848;
- ulong intstat, d;
- int i;
- bt848->intstat = intstat_i2cdone;
- d = (addr << 24) | (sub << 16) | tv->i2ccmd;
- if (both)
- d |= (data << 8) | i2c_bt848w3b;
- bt848->i2c = d;
- intstat = 0;
- for (i = 0; i != 1000; i++) {
- if ((intstat = bt848->intstat) & intstat_i2cdone)
- break;
- microdelay(1000);
- }
- if (i == i2c_timeout) {
- print("i2cwrite: timeout\n");
- return 0;
- }
- if ((intstat & intstat_i2crack) == 0)
- return 0;
- return 1;
- }
- static ulong *
- riscpacked(ulong paddr, int fnum, int w, int h, int stride, ulong **lastjmp)
- {
- ulong *p, *pbase;
- int i;
- pbase = p = (ulong *)malloc((h + 6) * 2 * sizeof(ulong));
- assert(p);
- assert(w <= 0x7FF);
- *p++ = riscsync | riscsync_resync | riscsync_vre;
- *p++ = 0;
- *p++ = riscsync | riscsync_fm1;
- *p++ = 0;
- for (i = 0; i != h / 2; i++) {
- *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol;
- *p++ = paddr + i * 2 * stride;
- }
- *p++ = riscsync | riscsync_resync | riscsync_vro;
- *p++ = 0;
- *p++ = riscsync | riscsync_fm1;
- *p++ = 0;
- for (i = 0; i != h / 2; i++) {
- *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol;
- *p++ = paddr + (i * 2 + 1) * stride;
- }
- // reset status. you really need two instructions ;-(.
- *p++ = riscjmp | (0xf << risclabelshift_reset);
- *p++ = PADDR(p);
- *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
- *lastjmp = p;
- return pbase;
- }
- static ulong *
- riscplanar411(ulong paddr, int fnum, int w, int h, ulong **lastjmp)
- {
- ulong *p, *pbase, Cw, Yw, Ch;
- uchar *Ybase, *Cbbase, *Crbase;
- int i, bitspp;
- bitspp = 6;
- assert(w * bitspp / 8 <= 0x7FF);
- pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong));
- assert(p);
- Yw = w;
- Ybase = (uchar *)paddr;
- Cw = w >> 1;
- Ch = h >> 1;
- Cbbase = Ybase + Yw * h;
- Crbase = Cbbase + Cw * Ch;
-
- *p++ = riscsync | riscsync_resync | riscsync_vre;
- *p++ = 0;
- *p++ = riscsync | riscsync_fm3;
- *p++ = 0;
- for (i = 0; i != h / 2; i++) {
- *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
- *p++ = (Cw << 16) | Cw;
- *p++ = (ulong)(Ybase + i * 2 * Yw);
- *p++ = (ulong)(Cbbase + i * Cw); // Do not interlace
- *p++ = (ulong)(Crbase + i * Cw);
- }
- *p++ = riscsync | riscsync_resync | riscsync_vro;
- *p++ = 0;
- *p++ = riscsync | riscsync_fm3;
- *p++ = 0;
- for (i = 0; i != h / 2; i++) {
- *p++ = riscwrite1s23 | Yw | riscwrite_sol | riscwrite_eol;
- *p++ = (Cw << 16) | Cw;
- *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw);
- }
- // reset status. you really need two instructions ;-(.
- *p++ = riscjmp | (0xf << risclabelshift_reset);
- *p++ = PADDR(p);
- *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
- *lastjmp = p;
- return pbase;
- }
- static ulong *
- riscplanar422(ulong paddr, int fnum, int w, int h, ulong **lastjmp)
- {
- ulong *p, *pbase, Cw, Yw;
- uchar *Ybase, *Cbbase, *Crbase;
- int i, bpp;
- bpp = 2;
- assert(w * bpp <= 0x7FF);
- pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong));
- assert(p);
- Yw = w;
- Ybase = (uchar *)paddr;
- Cw = w >> 1;
- Cbbase = Ybase + Yw * h;
- Crbase = Cbbase + Cw * h;
- *p++ = riscsync | riscsync_resync | riscsync_vre;
- *p++ = 0;
- *p++ = riscsync | riscsync_fm3;
- *p++ = 0;
- for (i = 0; i != h / 2; i++) {
- *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
- *p++ = (Cw << 16) | Cw;
- *p++ = (ulong)(Ybase + i * 2 * Yw);
- *p++ = (ulong)(Cbbase + i * 2 * Cw);
- *p++ = (ulong)(Crbase + i * 2 * Cw);
- }
- *p++ = riscsync | riscsync_resync | riscsync_vro;
- *p++ = 0;
- *p++ = riscsync | riscsync_fm3;
- *p++ = 0;
- for (i = 0; i != h / 2; i++) {
- *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
- *p++ = (Cw << 16) | Cw;
- *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw);
- *p++ = (ulong)(Cbbase + (i * 2 + 1) * Cw);
- *p++ = (ulong)(Crbase + (i * 2 + 1) * Cw);
- }
- // reset status. you really need two instructions ;-(.
- *p++ = riscjmp | (0xf << risclabelshift_reset);
- *p++ = PADDR(p);
- *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
- *lastjmp = p;
- return pbase;
- }
- static ulong *
- riscaudio(ulong paddr, int nblocks, int bsize)
- {
- ulong *p, *pbase;
- int i;
- pbase = p = (ulong *)malloc((nblocks + 3) * 2 * sizeof(ulong));
- assert(p);
- *p++ = riscsync|riscsync_fm1;
- *p++ = 0;
-
- for (i = 0; i != nblocks; i++) {
- *p++ = riscwrite | riscwrite_sol | riscwrite_eol | bsize | riscirq |
- ((i & 0xf) << risclabelshift_set) |
- ((~i & 0xf) << risclabelshift_reset);
- *p++ = paddr + i * bsize;
- }
- *p++ = riscsync | riscsync_vro;
- *p++ = 0;
- *p++ = riscjmp;
- *p++ = PADDR(pbase);
- USED(p);
- return pbase;
- }
- static void
- vactivate(Tv *tv, Frame *frames, int nframes)
- {
- Bt848 *bt848 = tv->bt848;
- ilock(tv);
- if (tv->frames) {
- iunlock(tv);
- error(Einuse);
- }
- poperror();
- tv->frames = frames;
- tv->nframes = nframes;
- bt848->riscstrtadd = PADDR(tv->frames[0].fstart);
- bt848->capctl |= capctl_captureodd|capctl_captureeven;
- bt848->gpiodmactl |= gpiodmactl_fifoenable;
- bt848->gpiodmactl |= gpiodmactl_riscenable;
-
- iunlock(tv);
- }
- static void
- vstart(Tv *tv, int nframes, int w, int h, int stride)
- {
- Frame *frames;
- int bitspp, i, bpf;
- if (nframes >= 0x10)
- error(Ebadarg);
- bitspp = getbitspp(tv);
- bpf = w * h * bitspp / 8;
- // Add one as a spare.
- frames = (Frame *)malloc(nframes * sizeof(Frame));
- assert(frames);
- if (waserror()) {
- for (i = 0; i != nframes; i++)
- if (frames[i].fbase)
- free(frames[i].fbase);
- free(frames);
- nexterror();
- }
- memset(frames, 0, nframes * sizeof(Frame));
- for (i = 0; i != nframes; i++) {
- if ((frames[i].fbase = (uchar *)malloc(bpf)) == nil)
- error(Enomem);
-
- switch (tv->cfmt) {
- case colorfmt_YCbCr422:
- frames[i].fstart = riscplanar422(PADDR(frames[i].fbase), i,
- w, h, &frames[i].fjmp);
- break;
- case colorfmt_YCbCr411:
- frames[i].fstart = riscplanar411(PADDR(frames[i].fbase), i,
- w, h, &frames[i].fjmp);
- break;
- case colorfmt_rgb16:
- frames[i].fstart = riscpacked(PADDR(frames[i].fbase), i,
- w * bitspp / 8, h, stride * bitspp / 8,
- &frames[i].fjmp);
- break;
- default:
- panic("vstart: Unsupport colorformat\n");
- }
- }
- for (i = 0; i != nframes; i++)
- *frames[i].fjmp =
- PADDR((i == nframes - 1)? frames[0].fstart: frames[i + 1].fstart);
- vactivate(tv, frames, nframes);
- }
- static void
- astart(Tv *tv, char *input, uint rate, uint nab, uint nasz)
- {
- Bt848 *bt878 = tv->bt878;
- ulong *arisc;
- int selector;
- uchar *abuf;
- int s, d;
- if (bt878 == nil || tv->amux == nil)
- error("#V: Card does not support audio");
- selector = 0;
- if (!strcmp(input, "tv"))
- selector = asel_tv;
- else if (!strcmp(input, "radio"))
- selector = asel_radio;
- else if (!strcmp(input, "mic"))
- selector = asel_mic;
- else if (!strcmp(input, "smxc"))
- selector = asel_smxc;
- else
- error("#V: Invalid input");
- if (nasz > 0xfff)
- error("#V: Audio block size too big (max 0xfff)");
- abuf = (uchar *)malloc(nab * nasz * sizeof(uchar));
- assert(abuf);
- arisc = riscaudio(PADDR(abuf), nab, nasz);
- ilock(tv);
- if (tv->arisc) {
- iunlock(tv);
- free(abuf);
- free(arisc);
- error(Einuse);
- }
- tv->arisc = arisc;
- tv->abuf = abuf;
- tv->nablocks = nab;
- tv->absize = nasz;
- bt878->riscstrtadd = PADDR(tv->arisc);
- bt878->packetlen = (nab << 16) | nasz;
- bt878->intmask =
- intstat_scerr | intstat_ocerr | intstat_risci |
- intstat_pabort | intstat_riperr | intstat_pperr |
- intstat_fdsr | intstat_ftrgt | intstat_fbus;
- /* Assume analog, 16bpp */
- for (s = 0; s < 16; s++)
- if (rate << s > Hwbase_ad * 4 / 15)
- break;
- for (d = 15; d >= 4; d--)
- if (rate << s < Hwbase_ad * 4 / d)
- break;
- print("astart: sampleshift %d, decimation %d\n", s, d);
- tv->narblocks = 0;
- bt878->gpiodmactl = gpiodmactl_fifoenable |
- gpiodmactl_riscenable | gpiodmactl_acapenable |
- gpiodmactl_daes2 | /* gpiodmactl_apwrdn | */
- gpiodmactl_daiomda | (d << 8) | (9 << 28) | (selector << 24);
- print("dmactl %.8ulX\n", bt878->gpiodmactl);
- iunlock(tv);
- }
- static void
- astop(Tv *tv)
- {
- Bt848 *bt878 = tv->bt878;
- ilock(tv);
- if (tv->aref.ref > 0) {
- iunlock(tv);
- error(Einuse);
- }
- if (tv->abuf) {
- bt878->gpiodmactl &= ~gpiodmactl_riscenable;
- bt878->gpiodmactl &= ~gpiodmactl_fifoenable;
- free(tv->abuf);
- tv->abuf = nil;
- free(tv->arisc);
- tv->arisc = nil;
- }
- iunlock(tv);
- }
- static void
- vgastart(Tv *tv, ulong paddr, int stride)
- {
- Frame *frame;
- frame = (Frame *)malloc(sizeof(Frame));
- assert(frame);
- if (waserror()) {
- free(frame);
- nexterror();
- }
- frame->fbase = nil;
- frame->fstart = riscpacked(paddr, 0, ntsc_hactive * getbitspp(tv) / 8,
- ntsc_vactive, stride * getbitspp(tv) / 8,
- &frame->fjmp);
- *frame->fjmp = PADDR(frame->fstart);
- vactivate(tv, frame, 1);
- }
- static void
- vstop(Tv *tv)
- {
- Bt848 *bt848 = tv->bt848;
- ilock(tv);
- if (tv->fref.ref > 0) {
- iunlock(tv);
- error(Einuse);
- }
- if (tv->frames) {
- int i;
- bt848->gpiodmactl &= ~gpiodmactl_riscenable;
- bt848->gpiodmactl &= ~gpiodmactl_fifoenable;
- bt848->capctl &= ~(capctl_captureodd|capctl_captureeven);
- for (i = 0; i != tv->nframes; i++)
- if (tv->frames[i].fbase)
- free(tv->frames[i].fbase);
- free(tv->frames);
- tv->frames = nil;
- }
- iunlock(tv);
- }
- static long
- hrcfreq[] = { /* HRC CATV frequencies */
- 0, 7200, 5400, 6000, 6600, 7800, 8400, 17400,
- 18000, 18600, 19200, 19800, 20400, 21000, 12000, 12600,
- 13200, 13800, 14400, 15000, 15600, 16200, 16800, 21600,
- 22200, 22800, 23400, 24000, 24600, 25200, 25800, 26400,
- 27000, 27600, 28200, 28800, 29400, 30000, 30600, 31200,
- 31800, 32400, 33000, 33600, 34200, 34800, 35400, 36000,
- 36600, 37200, 37800, 38400, 39000, 39600, 40200, 40800,
- 41400, 42000, 42600, 43200, 43800, 44400, 45000, 45600,
- 46200, 46800, 47400, 48000, 48600, 49200, 49800, 50400,
- 51000, 51600, 52200, 52800, 53400, 54000, 54600, 55200,
- 55800, 56400, 57000, 57600, 58200, 58800, 59400, 60000,
- 60600, 61200, 61800, 62400, 63000, 63600, 64200, 9000,
- 9600, 10200, 10800, 11400, 64800, 65400, 66000, 66600,
- 67200, 67800, 68400, 69000, 69600, 70200, 70800, 71400,
- 72000, 72600, 73200, 73800, 74400, 75000, 75600, 76200,
- 76800, 77400, 78000, 78600, 79200, 79800,
- };
- static void
- frequency(Tv *tv, int channel, int finetune)
- {
- Tuner *tuner = tv->tuner;
- long freq;
- ushort div;
- uchar cfg;
- if (channel < 0 || channel > nelem(hrcfreq))
- error(Ebadarg);
- freq = (hrcfreq[channel] * Freqmultiplier) / 100;
- if (freq < tuner->freq_vhfh)
- cfg = tuner->VHF_L;
- else if (freq < tuner->freq_uhf)
- cfg = tuner->VHF_H;
- else
- cfg = tuner->UHF;
- div = (freq + tuner->offs + finetune) & 0x7fff;
-
- if (!i2cwrite(tv, tv->i2ctuneraddr, (div >> 8) & 0x7f, div, 1))
- error(Eio);
-
- if (!i2cwrite(tv, tv->i2ctuneraddr, tuner->cfg, cfg, 1))
- error(Eio);
- tv->channel = channel;
- if (tv->msp)
- msptune(tv);
- }
- static struct {
- char *cmode;
- ulong realmode;
- ulong cbits;
- } colormodes[] = {
- { "RGB16", colorfmt_rgb16, colorfmt_rgb16, },
- { "YCbCr422", colorfmt_YCbCr422, colorfmt_YCbCr422, },
- { "YCbCr411", colorfmt_YCbCr411, colorfmt_YCbCr422, },
- };
- static void
- colormode(Tv *tv, char *colormode)
- {
- Bt848 *bt848 = tv->bt848;
- int i;
- for (i = 0; i != nelem(colormodes); i++)
- if (!strcmp(colormodes[i].cmode, colormode))
- break;
- if (i == nelem(colormodes))
- error(Ebadarg);
- tv->cfmt = colormodes[i].realmode;
- bt848->colorfmt = colormodes[i].cbits;
- }
- static int
- getbitspp(Tv *tv)
- {
- switch (tv->cfmt) {
- case colorfmt_rgb16:
- case colorfmt_YCbCr422:
- return 16;
- case colorfmt_YCbCr411:
- return 12;
- default:
- error("getbitspp: Unsupport color format\n");
- }
- return -1;
- }
- static char *
- getcolormode(ulong cmode)
- {
- switch (cmode) {
- case colorfmt_rgb16:
- return "RGB16";
- case colorfmt_YCbCr411:
- return "YCbCr411";
- case colorfmt_YCbCr422:
- return (cmode == colorfmt_YCbCr422)? "YCbCr422": "YCbCr411";
- default:
- error("getcolormode: Unsupport color format\n");
- }
- return nil;
- }
- static void
- i2c_set(Tv *tv, int scl, int sda)
- {
- Bt848 *bt848 = tv->bt848;
- ulong d;
- bt848->i2c = (scl << 1) | sda;
- d = bt848->i2c;
- USED(d);
- microdelay(i2c_delay);
- }
- static uchar
- i2c_getsda(Tv *tv)
- {
- Bt848 *bt848 = tv->bt848;
- return bt848->i2c & i2c_sda;
- }
- static void
- i2c_start(Tv *tv)
- {
- i2c_set(tv, 0, 1);
- i2c_set(tv, 1, 1);
- i2c_set(tv, 1, 0);
- i2c_set(tv, 0, 0);
- }
- static void
- i2c_stop(Tv *tv)
- {
- i2c_set(tv, 0, 0);
- i2c_set(tv, 1, 0);
- i2c_set(tv, 1, 1);
- }
- static void
- i2c_bit(Tv *tv, int sda)
- {
- i2c_set(tv, 0, sda);
- i2c_set(tv, 1, sda);
- i2c_set(tv, 0, sda);
- }
- static int
- i2c_getack(Tv *tv)
- {
- int ack;
- i2c_set(tv, 0, 1);
- i2c_set(tv, 1, 1);
- ack = i2c_getsda(tv);
- i2c_set(tv, 0, 1);
- return ack;
- }
- static int
- i2c_wr8(Tv *tv, uchar d, int wait)
- {
- int i, ack;
- i2c_set(tv, 0, 0);
- for (i = 0; i != 8; i++) {
- i2c_bit(tv, (d & 0x80)? 1: 0);
- d <<= 1;
- }
- if (wait)
- microdelay(wait);
- ack = i2c_getack(tv);
- return ack == 0;
- }
- static uchar
- i2c_rd8(Tv *tv, int lastbyte)
- {
- int i;
- uchar d;
- d = 0;
- i2c_set(tv, 0, 1);
- for (i = 0; i != 8; i++) {
- i2c_set(tv, 1, 1);
- d <<= 1;
- if (i2c_getsda(tv))
- d |= 1;
- i2c_set(tv, 0, 1);
- }
-
- i2c_bit(tv, lastbyte? 1: 0);
- return d;
- }
- static int
- mspsend(Tv *tv, uchar *cmd, int ncmd)
- {
- int i, j, delay;
- for (i = 0; i != 3; i++) {
- delay = 2000;
- i2c_start(tv);
- for (j = 0; j != ncmd; j++) {
- if (!i2c_wr8(tv, cmd[j], delay))
- break;
- delay = 0;
- }
- i2c_stop(tv);
- if (j == ncmd)
- return 1;
- microdelay(10000);
- print("mspsend: retrying\n");
- }
- return 0;
- }
- static int
- mspwrite(Tv *tv, uchar sub, ushort reg, ushort v)
- {
- uchar b[6];
- b[0] = i2c_msp3400;
- b[1] = sub;
- b[2] = reg >> 8;
- b[3] = reg;
- b[4] = v >> 8;
- b[5] = v;
- return mspsend(tv, b, sizeof b);
- }
- static int
- mspread(Tv *tv, uchar sub, ushort reg, ushort *data)
- {
- uchar b[4];
- int i;
- b[0] = i2c_msp3400;
- b[1] = sub;
- b[2] = reg >> 8;
- b[3] = reg;
- for (i = 0; i != 3; i++) {
- i2c_start(tv);
- if (!i2c_wr8(tv, b[0], 2000) ||
- !i2c_wr8(tv, b[1] | 1, 0) ||
- !i2c_wr8(tv, b[2], 0) ||
- !i2c_wr8(tv, b[3], 0)) {
- i2c_stop(tv);
- microdelay(10000);
- print("retrying\n");
- continue;
- }
- i2c_start(tv);
- if (!i2c_wr8(tv, b[0] | 1, 2000)) {
- i2c_stop(tv);
- continue;
- }
-
- *data = i2c_rd8(tv, 0) << 8;
- *data |= i2c_rd8(tv, 1);
- i2c_stop(tv);
- return 1;
- }
- return 0;
- }
- static uchar mspt_reset[] = { i2c_msp3400, 0, 0x80, 0 };
- static uchar mspt_on[] = { i2c_msp3400, 0, 0, 0 };
- static int
- mspreset(Tv *tv)
- {
- ushort v, p;
- Bt848 *bt848 = tv->bt848;
- ulong b;
- b = 1 << 5;
- gpioenable(tv, ~b, b);
- gpiowrite(tv, ~b, 0);
- microdelay(2500);
- gpiowrite(tv, ~b, b);
- bt848->i2c = 0x80;
- microdelay(2000);
- mspsend(tv, mspt_reset, sizeof mspt_reset);
- microdelay(2000);
- if (!mspsend(tv, mspt_on, sizeof mspt_on)) {
- print("#V: Cannot find MSP34x5G on the I2C bus (on)\n");
- return 0;
- }
- microdelay(2000);
- if (!mspread(tv, msp_bbp, 0x001e, &v)) {
- print("#V: Cannot read MSP34xG5 chip version\n");
- return 0;
- }
- if (!mspread(tv, msp_bbp, 0x001f, &p)) {
- print("#V: Cannot read MSP34xG5 product code\n");
- return 0;
- }
- print("#V: MSP34%dg ROM %.d, %d.%d\n",
- (uchar)(p >> 8), (uchar)p, (uchar)(v >> 8), (uchar)v);
- tv->msp = 1;
- return 1;
- }
- static void
- mspvolume(Tv *tv, int mute, int l, int r)
- {
- short v, d;
- ushort b;
- if (mute) {
- v = 0;
- b = 0;
- }
- else {
- tv->aleft = l;
- tv->aright = r;
- d = v = max(l, r);
- if (d == 0)
- d++;
- b = ((r - l) * 0x7f) / d;
- }
- mspwrite(tv, msp_bbp, 0, v << 8);
- mspwrite(tv, msp_bbp, 7, v? 0x4000: 0);
- mspwrite(tv, msp_bbp, 1, b << 8);
- }
- static char *
- mspaformat(int f)
- {
- switch (f) {
- case 0:
- return "unknown";
- case 2:
- case 0x20:
- case 0x30:
- return "M-BTSC";
- case 3:
- return "B/G-FM";
- case 4:
- case 9:
- case 0xB:
- return "L-AM/NICAM D/Kn";
- case 8:
- return "B/G-NICAM";
- case 0xA:
- return "I";
- case 0x40:
- return "FM-Radio";
- }
- return "unknown format";
- }
-
- static void
- msptune(Tv *tv)
- {
- ushort d, s, nicam;
- int i;
- mspvolume(tv, 1, 0, 0);
- if (!mspwrite(tv, msp_dem, 0x0030, 0x2033))
- error("#V: Cannot set MODUS register");
- if (!mspwrite(tv, msp_bbp, 0x0008, 0x0320))
- error("#V: Cannot set loadspeaker input");
- if (!mspwrite(tv, msp_dem, 0x0040, 0x0001))
- error("#V: Cannot set I2S clock freq");
- if (!mspwrite(tv, msp_bbp, 0x000d, 0x1900))
- error("#V: Cannot set SCART prescale");
- if (!mspwrite(tv, msp_bbp, 0x000e, 0x2403))
- error("#V: Cannot set FM/AM prescale");
- if (!mspwrite(tv, msp_bbp, 0x0010, 0x5a00))
- error("#V: Cannot set NICAM prescale");
- if (!mspwrite(tv, msp_dem, 0x0020, 0x0001))
- error("#V: Cannot start auto detect");
- for (d = (ushort)-1, i = 0; i != 10; i++) {
- if (!mspread(tv, msp_dem, 0x007e, &d))
- error("#V: Cannot get autodetect info MSP34xG5");
- if (d == 0 || d < 0x800)
- break;
- delay(50);
- }
- if (!mspread(tv, msp_dem, 0x0200, &s))
- error("#V: Cannot get status info MSP34xG5");
- mspvolume(tv, 0, tv->aleft, tv->aright);
- nicam = ((s >> 4) & 2) | ((s >> 9) & 1);
- snprint(tv->ainfo, sizeof tv->ainfo, "%s %s %s",
- mspaformat(d), (s & (1 << 6))? "stereo": "mono",
- nicamstate[nicam]);
- }
- static void
- i2cscan(Tv *tv)
- {
- int i, ack;
- for (i = 0; i < 0x100; i += 2) {
- i2c_start(tv);
- ack = i2c_wr8(tv, i, 0);
- i2c_stop(tv);
- if (ack) {
- print("i2c device @%.2uX\n", i);
- }
- }
- for (i = 0xf0; i != 0xff; i++) {
- i2c_start(tv);
- ack = i2c_wr8(tv, i, 0);
- i2c_stop(tv);
- if (ack)
- print("i2c device may be at @%.2uX\n", i);
- }
- }
- static void
- gpioenable(Tv *tv, ulong mask, ulong data)
- {
- Bt848 *bt848 = tv->bt848;
- bt848->gpioouten = (bt848->gpioouten & mask) | data;
- }
- static void
- gpiowrite(Tv *tv, ulong mask, ulong data)
- {
- Bt848 *bt848 = tv->bt848;
- bt848->gpiodata[0] = (bt848->gpiodata[0] & mask) | data;
- }
- static void
- alteraoutput(Tv *tv)
- {
- if (tv->gpiostate == Gpiooutput)
- return;
- gpioenable(tv, ~0xffffff, 0x56ffff);
- microdelay(10);
- tv->gpiostate = Gpiooutput;
- }
- static void
- alterainput(Tv *tv)
- {
- if (tv->gpiostate == Gpioinput)
- return;
- gpioenable(tv, ~0xffffff, 0x570000);
- microdelay(10);
- tv->gpiostate = Gpioinput;
- }
- static void
- alterareg(Tv *tv, ulong reg)
- {
- if (tv->alterareg == reg)
- return;
- gpiowrite(tv, ~0x56ffff, (reg & 0x54ffff) | tv->alteraclock);
- microdelay(10);
- tv->alterareg = reg;
- }
- static void
- alterawrite(Tv *tv, ulong reg, ushort data)
- {
- alteraoutput(tv);
- alterareg(tv, reg);
- tv->alteraclock ^= 0x20000;
- gpiowrite(tv, ~0x56ffff, (reg & 0x540000) | data | tv->alteraclock);
- microdelay(10);
- }
- static void
- alteraread(Tv *tv, int reg, ushort *data)
- {
- Bt848 *bt848 = tv->bt848;
- if (tv->alterareg != reg) {
- alteraoutput(tv);
- alterareg(tv, reg);
- }
- else {
- gpioenable(tv, ~0xffffff, 0x560000);
- microdelay(10);
- }
- alterainput(tv);
- gpiowrite(tv, ~0x570000, (reg & 0x560000) | tv->alteraclock);
- microdelay(10);
- *data = (ushort)bt848->gpiodata[0];
- microdelay(10);
- }
- static void
- kfirloadu(Tv *tv, uchar *u, int ulen)
- {
- Bt848 *bt848 = tv->bt848;
- int i, j;
- ilock(&tv->kfirlock);
- bt848->gpioouten &= 0xff000000;
- bt848->gpioouten |= gpio_altera_data |
- gpio_altera_clock | gpio_altera_nconfig;
- bt848->gpiodata[0] &= 0xff000000;
- microdelay(10);
- bt848->gpiodata[0] |= gpio_altera_nconfig;
- microdelay(10);
- // Download the microcode
- for (i = 0; i != ulen; i++)
- for (j = 0; j != 8; j++) {
- bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data);
- if (u[i] & 1)
- bt848->gpiodata[0] |= gpio_altera_data;
- bt848->gpiodata[0] |= gpio_altera_clock;
- u[i] >>= 1;
- }
- bt848->gpiodata[0] &= ~gpio_altera_clock;
- microdelay(100);
- // Initialize.
- for (i = 0; i != 30; i++) {
- bt848->gpiodata[0] &= ~gpio_altera_clock;
- bt848->gpiodata[0] |= gpio_altera_clock;
- }
- bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data);
- iunlock(&tv->kfirlock);
- tv->gpiostate = Gpioinit;
- }
- static void
- kfirreset(Tv *tv)
- {
- alterawrite(tv, 0, 0);
- microdelay(10);
- alterawrite(tv, 0x40000, 0);
- microdelay(10);
- alterawrite(tv, 0x40006, 0x80);
- microdelay(10);
- alterawrite(tv, 8, 1);
- microdelay(10);
- alterawrite(tv, 0x40004, 2);
- microdelay(10);
- alterawrite(tv, 4, 3);
- microdelay(3);
- }
- static int
- kfirinitialize(Tv *tv)
- {
- // Initialize parameters?
- tv->gpiostate = Gpioinit;
- tv->alterareg = -1;
- tv->alteraclock = 0x20000;
- kfirloadu(tv, hcwAMC, sizeof hcwAMC);
- kfirreset(tv);
- return 1;
- }
|