All pastes #921830 Raw Edit

Miscellany

public c v1 · immutable
#921830 ·published 2008-02-28 11:10 UTC
rendered paste body
#include <sys/param.h>#include <sys/kernel.h>#include <sys/module.h>#include <sys/bus.h>#include <machine/bus.h>#include <machine/resource.h>#include <sys/rman.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/signal.h>#include <sys/signalvar.h>#include <sys/lock.h>#include <sys/mutex.h>#include <dev/pci/pcivar.h>#include <dev/pci/pcireg.h>#include <dev/iicbus/iiconf.h>#include "iicbus_if.h"#include <vm/vm.h>#include <vm/vm_extern.h>#include <vm/pmap.h>                /* req. by machine/pmap.h       */#include <machine/pmap.h>           /* vtophys                      */#include <vm/vm_map.h>#include <vm/vm_object.h>#include <vm/vm_kern.h>#include "saa713x_reg.h"#include "saa713x_ioctl.h"#include "saa713x_var.h"#include "saa713x_i2c.h"#include "saa713x_video.h"#include "saa713x_audio.h"static void saa_intr(void *arg);static device_probe_t		saa_probe;static device_attach_t 		saa_attach;static device_detach_t 		saa_detach;static device_shutdown_t	saa_shutdown;static bus_print_child_t	saa_print_child;static device_method_t saa_methods[] = {	DEVMETHOD(device_probe, 	saa_probe),	DEVMETHOD(device_attach, 	saa_attach),	DEVMETHOD(device_detach, 	saa_detach),	DEVMETHOD(device_shutdown, 	saa_shutdown),	DEVMETHOD(bus_print_child,	saa_print_child),        DEVMETHOD(iicbus_callback, 	iicbus_null_callback),        DEVMETHOD(iicbus_repeated_start, saa_i2c_start),        DEVMETHOD(iicbus_start, 	saa_i2c_start),        DEVMETHOD(iicbus_stop, 		saa_i2c_stop),        DEVMETHOD(iicbus_write, 	saa_i2c_write),        DEVMETHOD(iicbus_read, 		saa_i2c_read),        DEVMETHOD(iicbus_reset, 	saa_i2c_reset),	{ 0, 0 }};static driver_t saa_driver = {	"saa",	saa_methods,	sizeof(struct saa_softc)};devclass_t saa_devclass;DRIVER_MODULE(saa, pci, saa_driver, saa_devclass, 0, 0);MODULE_VERSION(saa, 1);MODULE_DEPEND(saa, iicbus, 1, 1, 1);#ifdef SAA_DSHMMODULE_DEPEND(saa, sysvshm, 1, 1, 1);#endifextern driver_t iicbus_driver;extern devclass_t iicbus_devclass;DRIVER_MODULE(iicbus, saa, iicbus_driver, iicbus_devclass, 0, 0);static intsaa_print_child(device_t d, device_t child){	device_printf(child, "<SAA713x I2C Controller> on saa%d\n",			device_get_unit(d));	return 0;}struct saa_spprt_dev {	uint16_t	sdv_vendor_id;	uint16_t	sdv_dev_id;	const char	*sdv_dev_desc;};static struct saa_spprt_dev spprt_devs[] = {	{ SAA_VENDOR_ID, SAA7130_DEV_ID, 				"Philips SAA7130 AV broadcast decoder" },	{ SAA_VENDOR_ID, SAA7133_DEV_ID,				"Philips SAA7133 AV broadcast decoder" },	{ SAA_VENDOR_ID, SAA7134_DEV_ID,				"Philips SAA7134 AV broadcast decoder" },	{ SAA_VENDOR_ID, SAA7135_DEV_ID,				"Philips SAA7135 AV broadcast decoder" },	{ 0, 0, 0 }};static intsaa_probe(device_t dev){	uint16_t did, vid;	int i;	vid = pci_get_vendor(dev);	did = pci_get_device(dev);		i = 0;	while(spprt_devs[i].sdv_vendor_id != 0) {		if (vid == spprt_devs[i].sdv_vendor_id &&		    did == spprt_devs[i].sdv_dev_id) {			device_set_desc(dev, spprt_devs[i].sdv_dev_desc);			return 0;		}		++i;	}	return ENXIO;}static voidpta_dma_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error){	struct saa_softc *sc = (struct saa_softc*)arg;	int i, j;		if (error == EFBIG) {		sc->sc_pta_map_loaderror = EFBIG;		wakeup(sc);		return;	}		i = 0;	while (i < nsegs) {		j = 0;		while(j < segs[i].ds_len && 			sc->sc_pta_map_loadidx < SAA_DMA_NRCHANS) {			sc->sc_pta_paddr[sc->sc_pta_map_loadidx++] =				segs[i].ds_addr + j;			j += 4096;		}		++i;	}	if (sc->sc_pta_map_loadidx == SAA_DMA_NRCHANS)		wakeup(sc);}static intsaa_free_pta(struct saa_softc *sc){	int rval = 0;	if (sc->sc_pta_map_unloadflag) 		bus_dmamap_unload(sc->sc_pta_tag,					sc->sc_pta_map);		if (sc->sc_pta_map_destroyflag)		bus_dmamem_free(sc->sc_pta_tag,					sc->sc_pta,					sc->sc_pta_map);	if (!rval && sc->sc_pta_tag)		rval = bus_dma_tag_destroy(sc->sc_pta_tag);		return rval;}static intsaa_alloc_pta(struct saa_softc *sc){	int rval, sz;		sz = 4096 * SAA_DMA_NRCHANS;	sc->sc_pta_map_destroyflag = 0;	sc->sc_pta_map_unloadflag = 0;	if (bus_dma_tag_create(0, 			4096, 0,			BUS_SPACE_MAXADDR_32BIT,			BUS_SPACE_MAXADDR,			0, 0,			sz, 1, sz,			0,				0, 0,			&sc->sc_pta_tag) != 0) {		device_printf(sc->sc_dev, "Error creating pta tag\n");		return EAGAIN;	}		if (bus_dmamem_alloc(sc->sc_pta_tag,			(void**)&sc->sc_pta,			BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT,			&sc->sc_pta_map) != 0) {		device_printf(sc->sc_dev, "Error allocating pta memory\n");		return EAGAIN;	}	sc->sc_pta_map_destroyflag = 1;	sc->sc_pta_map_loadidx = 0;	sc->sc_pta_map_loaderror = 0;	rval = bus_dmamap_load(sc->sc_pta_tag,			sc->sc_pta_map,			sc->sc_pta, sz,			pta_dma_cb, sc,			0);	if (rval == EINPROGRESS)		tsleep(sc, PRI_MAX_KERN, "dmapld", 0);	else if (rval != 0) {		device_printf(sc->sc_dev, "Error loading pta map\n");		return rval;	}	if (sc->sc_pta_map_loaderror != 0) {		device_printf(sc->sc_dev, "Error, callback failed "					"to load pta map (%d)\n",					sc->sc_pta_map_loadidx);		return EAGAIN;	}	sc->sc_pta_map_unloadflag = 1;	return 0;}	static intrelease_resources(struct saa_softc *sc){	int rval = 0;	if (saa_audio_dnit(sc) != 0)		device_printf(sc->sc_dev, "Error audio_dnit failed\n");	if (saa_video_dnit(sc) != 0)		device_printf(sc->sc_dev, "Error video_dnit failed\n");	if (saa_free_pta(sc) != 0)		device_printf(sc->sc_dev, "Error freeing pta memory\n");	if (!rval && sc->sc_intr_cookie != 0) 		rval = bus_teardown_intr(sc->sc_dev, 						sc->sc_intr_res,						sc->sc_intr_cookie);	if (!rval && sc->sc_intr_res)		rval = bus_release_resource(sc->sc_dev, SYS_RES_IRQ,						sc->sc_intr_rid, 						sc->sc_intr_res);	if (!rval && sc->sc_iicbus_dev)		rval = device_delete_child(sc->sc_dev, sc->sc_iicbus_dev);	if (!rval && sc->sc_base_res)		rval = bus_release_resource(sc->sc_dev, SYS_RES_MEMORY,			   			sc->sc_base_rid, 						sc->sc_base_res);	return rval;}static intsaa_attach(device_t dev){	struct saa_softc *sc;	const char *emsg;	sc = (struct saa_softc *)device_get_softc(dev);		sc->sc_dev = dev;	sc->sc_base_rid = SAA_PCIR_MEMBASE;	sc->sc_base_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 						&sc->sc_base_rid,						0, ~0, 1, RF_ACTIVE);	if (!sc->sc_base_res) {		emsg = "Error allocating resource (BASEPTR)";		goto attach_failed;	}	sc->sc_base_bustag = rman_get_bustag(sc->sc_base_res);	sc->sc_base_bushandle = rman_get_bushandle(sc->sc_base_res);	pci_enable_busmaster(dev);	REG_WRITE(REG_IEN, 0);	REG_WRITE(REG_FIEN, 0);	REG_WRITE(REG_MCR, 0);	REG_WRITE(REG_IREP, REG_READ(REG_IREP));/* reset pend. interrupts */	/* FIFO is set in capture, and overlay depending on format */	FIFO_SET_THRESH(0, 0, 0, 0);			/* XXX */	if (saa_alloc_pta(sc) != 0) {		emsg = "Error allocating device pta memory";		goto attach_failed;	}	sc->sc_iicbus_dev = device_add_child(dev, "iicbus", -1);	if (!sc->sc_iicbus_dev ||	    bus_generic_attach(sc->sc_dev)) {		emsg = "Error adding iicbus device";		goto attach_failed;	}	sc->sc_intr_rid = 0;	sc->sc_intr_res = bus_alloc_resource(dev, SYS_RES_IRQ, 						&sc->sc_intr_rid, 0, ~0, 1,						RF_ACTIVE | RF_SHAREABLE);	if (!sc->sc_intr_res) {		emsg = "Error allocating interrupt resource";		goto attach_failed;	}	if (bus_setup_intr(dev, sc->sc_intr_res, INTR_TYPE_AV | INTR_MPSAFE,				NULL, saa_intr, sc, &sc->sc_intr_cookie) != 0) {		emsg = "Error setting up interrupt";		goto attach_failed;	}	if (saa_video_init(sc) != 0) {		emsg = "Error initialising video subsection";		goto attach_failed;	}	if (saa_audio_init(sc) != 0) {		emsg = "Error initialising audio subsection";		goto attach_failed;	}	return 0;attach_failed:	device_printf(dev, "%s\n", emsg);	if (release_resources(sc) != 0)		device_printf(dev, "Error releasing some/all resources\n");	return ENODEV;}static intsaa_detach(device_t dev){	int rval;	struct saa_softc *sc = (struct saa_softc *)device_get_softc(dev);	REG_WRITE(REG_IEN, 0);	REG_WRITE(REG_FIEN, 0);	REG_WRITE(REG_MCR, 0);	if ( (rval = release_resources(sc)) != 0)		device_printf(dev, "Error releasing some/all resources\n");	return rval;}static intsaa_shutdown(device_t dev){	struct saa_softc *sc = (struct saa_softc *)device_get_softc(dev);	REG_WRITE(REG_IEN, 0);	REG_WRITE(REG_FIEN, 0);	REG_WRITE(REG_MCR, 0);	return 0;}static voidsaa_intr(void *arg){	struct saa_softc *sc = (struct saa_softc *)arg;	uint32_t irep, ists, avsts, r, sflag;	struct proc *p;	irep = REG_READ(REG_IREP);	sc->sc_sts->ssts_irep = irep;	ists = REG_READ(REG_ISTS);	avsts = REG_READ(REG_AVSTS);	sc->sc_sts->ssts_video_sts = avsts;#if 0	device_printf(sc->sc_dev, "INTR: AVSTS (0x%x) IREP(0x%x) "			"ISTS(0x%x)\n",			avsts,			irep,			ists);#endif	sc->sc_sts->ssts_sig_video = 0;	sc->sc_sts->ssts_sig_audio = 0;	sc->sc_sts->ssts_sig_sts = 0;	if ((irep >> 4) & sc->sc_video_spec.svs_cap_sigmask)		sc->sc_sts->ssts_sig_sts = 1;	sc->sc_sts->ssts_audio_vptr = REG_READ(REG_SLICE3_STS);	if (irep & IREP_SLICE3) {		sc->sc_sts->ssts_audio_lastbuf = ((ists >> 28) & 1);		sc->sc_sts->ssts_sig_audio = 1;		++sc->sc_sts->ssts_audio_framectr;		if (sc->sc_sts->ssts_audio_mb_count > 1)			saa_audio_multibuf_switchbuf(sc);		}	if (irep & IREP_SLICE0) {		r = REG_READ(REG_SLICE0_STS);		sc->sc_sts->ssts_video_vptr = r;		if ((r & SLICE_STS_SOURCE) == 0) {/* Video region*/			sc->sc_sts->ssts_sig_video = 1;			/* Only switch buffer at end of frames (ie. fld-2) */			if ((ists & ISTS_SLICE0_FEILD) != 0) {				/* Feild 2 (aka. EVEN) */				++sc->sc_sts->ssts_video_framectr;				if ((r & SLICE_STS_TASK) == 0) {					++sc->sc_sts->ssts_video_t1_framectr;					sc->sc_sts->ssts_video_lasttask = 0;				} else {					++sc->sc_sts->ssts_video_t2_framectr;					sc->sc_sts->ssts_video_lasttask = 1;				}				sc->sc_sts->ssts_video_feild = 0;				if (sc->sc_sts->ssts_video_mb_count > 1)					saa_video_multibuf_switchbuf(sc);				} else {				/* Feild 1 (aka. ODD) */				if ((r & SLICE_STS_TASK) == 0)					sc->sc_sts->ssts_video_lasttask = 0;				else					sc->sc_sts->ssts_video_lasttask = 1;				sc->sc_sts->ssts_video_feild = 1;			}		}	}	/* SFLAG is used to optimise when sc_video_capbuf_sigpid is 	 * is equal sc_audio_capbuf_sigpid	 */	sflag = 0;	/* USR1 - video capture	 * USR2 - audio capture, status	 * When both SIGUSR2 and USR1 are applicable send only USR1	 * client should check ssts_sig_*	 *	 * Interrupts are selectivly enabled based on svs_flags  	 * hence we optimise the if conditions by ORing 	 * CAPTURE_SIGNAL and STATUS_SIGNAL without causing any	 * ill effects (e.g. delivering sig_video when CAPTURE_SIGNAL	 * is not set)	 */	/* Video Process */	if ((sc->sc_sts->ssts_sig_video | sc->sc_sts->ssts_sig_sts) &&	    (sc->sc_video_spec.svs_flags & 		(VSPEC_FLAG_CAPTURE_SIGNAL | VSPEC_FLAG_STATUS_SIGNAL)) &&	    sc->sc_video_capbuf_sigpid != 0) 	{		if (sc->sc_sts->ssts_sig_video) {		    if ((p = pfind(sc->sc_video_capbuf_sigpid)) != NULL) {			psignal(p, SIGUSR1);			PROC_UNLOCK(p);			++sflag;		    } else			sc->sc_video_capbuf_sigpid = 0;		} else {		    if ((p = pfind(sc->sc_video_capbuf_sigpid)) != NULL) {			psignal(p, SIGUSR2);			PROC_UNLOCK(p);			++sflag;		    } else			sc->sc_video_capbuf_sigpid = 0;		}	}	/* Audio Process */	if ((sc->sc_sts->ssts_sig_audio | sc->sc_sts->ssts_sig_sts) &&	    (sc->sc_audio_spec.sas_flags & 		(ASPEC_FLAG_CAPTURE_SIGNAL | ASPEC_FLAG_STATUS_SIGNAL)) &&	    sc->sc_audio_capbuf_sigpid != 0) 	{	    if (sflag == 0 || 		(sc->sc_audio_capbuf_sigpid != 				sc->sc_video_capbuf_sigpid)) {		if ((p = pfind(sc->sc_audio_capbuf_sigpid)) != NULL) {			psignal(p, SIGUSR2);			PROC_UNLOCK(p);	    	} else			sc->sc_audio_capbuf_sigpid = 0;	    }	}	sc->sc_sts->ssts_video_sig_count += sc->sc_sts->ssts_sig_video;	sc->sc_sts->ssts_audio_sig_count += sc->sc_sts->ssts_sig_audio;	REG_WRITE(REG_ISTS, ists);	REG_WRITE(REG_IREP, irep);}void saa_build_pta(struct saa_softc *sc, 		bus_dma_segment_t *segs, int nsegs, 		uint32_t *pta){	int pta_idx, seg_idx, seg_offset;	pta_idx = seg_offset = seg_idx = 0;	/* Invariant nsegs > 0 */ 	while(pta_idx < 1024) {		pta[pta_idx++] = segs[seg_idx].ds_addr + seg_offset;		seg_offset += 4096;		if (seg_offset >= segs[seg_idx].ds_len) {			seg_offset = 0;			if ( ++seg_idx >= nsegs)				break;			if ((segs[seg_idx].ds_len % 4096) != 0)				panic("saa:saa_build_pta: Invalid segment len "					"= %td idx = %d\n",					segs[seg_idx].ds_len, seg_idx);		}	}}