*** sys/dev/bktr/bktr_core.c.orig	Fri Sep  1 12:26:08 2006
--- sys/dev/bktr/bktr_core.c	Tue Jan 30 08:32:11 2007
***************
*** 2503,2508 ****
--- 2503,2582 ----
  		}
  #endif /* STATUS_SUM */
  
+ 	case KODICOM_SET_IN:
+ 		mtx_lock(&bktr->kmaster->kmutex);
+ 		temp = *(unsigned char *)arg;
+ 		if (temp < 0 || temp > 15 || bktr->kmaster == NULL) {
+ 			mtx_unlock(&bktr->kmaster->kmutex);
+ 			return( EINVAL );
+ 		}			/* XXX should we stop the FIFO? XXX */
+ 		if (temp != bktr->kinput) {
+ 			kodicom_setgpioen(bktr->kmaster);
+ 
+ 				/* remove the old input */
+ 			kodicom_setcamera(bktr->kmaster, bktr->kunit,
+ 					  bktr->kinput, 0);
+ 			kodicom_setcamera(bktr->kmaster, bktr->kunit,
+ 					  bktr->kinput, KODICOM_STROBE);
+ 			kodicom_setcamera(bktr->kmaster, bktr->kunit,
+ 					  bktr->kinput, 0);
+ 			bktr->kinput = temp;
+ 				/* add the new input */
+ 			kodicom_setcamera(bktr->kmaster, bktr->kunit,
+ 					  bktr->kinput, KODICOM_ACTIVE);
+ 			kodicom_setcamera(bktr->kmaster, bktr->kunit,
+ 					  bktr->kinput, KODICOM_ACTIVE | KODICOM_STROBE);
+ 			kodicom_setcamera(bktr->kmaster, bktr->kunit,
+ 					  bktr->kinput, KODICOM_ACTIVE);
+ 		}
+ 		mtx_unlock(&bktr->kmaster->kmutex);
+ 		break;
+ 
+ 	case KODICOM_GET_IN:
+ 		if (bktr->kmaster == NULL) 
+ 			return( EINVAL );
+ 		 *(unsigned char *)arg = bktr->kinput;
+ 		break;
+ 
+ 	case KODICOM_SET_OUT:
+ 		mtx_lock(&bktr->kmaster->kmutex);
+ 		temp = *(unsigned char *)arg;
+ 		if ((temp != 255 && (temp < 0 || temp > 15)) ||
+ 		     bktr->kmaster == NULL) {
+ 			mtx_unlock(&bktr->kmaster->kmutex);
+ 			return( EINVAL );
+ 		}
+ 		if (temp != bktr->kmaster->koutput) {
+ 			kodicom_setgpioen(bktr->kmaster);
+ 				/* remove the old input */
+ 			if (bktr->kmaster->koutput != 255) {
+ 				kodicom_setcamera(bktr->kmaster, KODICOM_OUTPUT,
+ 						  bktr->koutput, 0);
+ 				kodicom_setcamera(bktr->kmaster, KODICOM_OUTPUT,
+ 						  bktr->koutput, KODICOM_STROBE);
+ 				kodicom_setcamera(bktr->kmaster, KODICOM_OUTPUT,
+ 						  bktr->koutput, 0);
+ 			}
+ 			if (temp != 255) {
+ 				bktr->kmaster->koutput = temp;
+ 				kodicom_setgpioen(bktr->kmaster);
+ 				kodicom_setcamera(bktr->kmaster, KODICOM_OUTPUT,
+ 						 bktr->koutput, KODICOM_ACTIVE);
+ 				kodicom_setcamera(bktr->kmaster, KODICOM_OUTPUT,
+ 						 bktr->koutput, KODICOM_ACTIVE | KODICOM_STROBE);
+ 				kodicom_setcamera(bktr->kmaster, KODICOM_OUTPUT,
+ 						 bktr->koutput, KODICOM_ACTIVE);
+ 
+ 			}
+ 		}
+ 		mtx_unlock(&bktr->kmaster->kmutex);
+ 		break;
+ 
+ 	case KODICOM_GET_OUT:
+ 		if (bktr->kmaster == NULL) 
+ 			return( EINVAL );
+ 		 *(unsigned char *)arg = bktr->kmaster->koutput;
+ 		break;
  	default:
  		return( ENOTTY );
  	}
*** sys/dev/bktr/bktr_core.h.orig	Wed Jan  5 19:42:31 2005
--- sys/dev/bktr/bktr_core.h	Wed Nov 29 14:46:01 2006
***************
*** 94,96 ****
--- 94,104 ----
  int	vbi_close( bktr_ptr_t bktr );
  int	vbi_read( bktr_ptr_t bktr, struct uio *uio, int ioflag );
  
+ /* kodicom routines */
+ #define KODICOM_RESET (1 << 9)
+ #define KODICOM_STROBE 0x100
+ #define KODICOM_ACTIVE 0x80
+ #define KODICOM_OUTPUT 0x4
+ void kodicom_setcamera(struct bktr_softc *m, int device, int camera, int control);
+ void kodicom_setgpioen(struct bktr_softc *m);
+ 
*** sys/dev/bktr/bktr_os.c.orig	Thu Aug 31 11:42:22 2006
--- sys/dev/bktr/bktr_os.c	Tue Jan 30 07:45:56 2007
***************
*** 455,460 ****
--- 455,533 ----
  	}
  #endif
  
+ #define PCI_VENDOR_PLX 0x3388
+ #define PCI_PRODUCT_PLX_PCITOPCIBRIDGE 0x0021
+ 	{
+ 	device_t parent, child;
+ 	unsigned int type = 0;
+ 	struct bktr_softc *mbktr, *sbktr;
+ 	int i;
+ 		/* bktr are detected out of order */
+ 	static unsigned korder[4] = {3, 0, 2, 1};
+ 
+ 		/* see if grandparent is a PLX PCI-PCI bridge */
+ 	if ((parent = device_get_parent(dev)) != NULL &&
+ 	    (child = device_get_parent(parent)) != NULL) 
+ 		type = pci_get_devid(child);
+ 
+ 	if (type != 0 && PCI_VENDOR(type) == PCI_VENDOR_PLX &&
+ 	    (PCI_PRODUCT(type) == PCI_PRODUCT_PLX_PCITOPCIBRIDGE) &&
+ 	    pci_get_slot(dev) == 15 && unit > 2) {
+ 		/* locate a master candidate (will be second device) */
+ 		if ((child = device_find_child(parent, "bktr", unit-2)) == NULL)
+ 			goto notkodicom;
+ 		mbktr = device_get_softc(child);
+ 		/* intitialize the 4 sibling bktr devices */
+ 		for (i=3; i >= 0; --i) {
+ 			if ((child = device_find_child(parent, "bktr", unit-i))
+ 							 == NULL) {
+ 				/* remove old settings, should not be used */
+ 				while (++i < 4) {
+ 						/* child was found before */
+ 					if ((child = device_find_child(parent,
+ 						 "bktr", unit-i)) == NULL) 
+ 							continue; /* XXX! */
+ 					sbktr = device_get_softc(child);
+ 					sbktr->kmaster = NULL;
+ 					sbktr->kunit = sbktr->kinput = 0;
+ 				}
+ 				goto notkodicom;
+ 			}
+ 			sbktr = device_get_softc(child);
+ 			sbktr->kmaster = mbktr; /* save the master device */
+ 				/* there are 4 BKTR per kodicom 4400 */
+ 			sbktr->kunit = korder[3 - i];
+ 			sbktr->kinput = 3 - i;
+ 			mtx_init(&sbktr->kmutex, "bktr crossbar", NULL, MTX_DEF);
+ 		}
+ 		mbktr->koutput = 255;	/* no output yet */
+ 
+ 		/* initialize the kodicom 4400 crossbar.
+ 		 * bit 9 is RESET.
+ 		 * bit 8 is STROBE value in.
+ 		 * bit 7 is active the crossbar rule.
+ 		 * bits 4-6 is OUTPUT selection:
+ 		 *  values of 0-3 selects the BT878s.
+ 		 *  value of 4 selects the OUTPUT port.
+ 		 *  values of 5-7 are not used.
+ 		 * bits 0-3 selects the 16 CAMERA inputs.
+ 		 *  cameras 0-3 are shared on the edge pins and
+ 		 *  on the external jacks.
+ 		 *
+ 		 * the second bktr device is the master.
+ 		 */
+ 		printf("kodicom master is %s\n", bktr_name(mbktr));
+ 		kodicom_setgpioen(mbktr);
+ 		OUTL(mbktr, BKTR_GPIO_DATA, KODICOM_RESET);   /* reset MUX */
+ 		OUTL(mbktr, BKTR_GPIO_DATA, 0);
+ 		for (i=0; i<4; i++) {
+ 			kodicom_setcamera(mbktr, korder[i], i, KODICOM_ACTIVE); 
+ 			kodicom_setcamera(mbktr, korder[i], i, (KODICOM_STROBE | KODICOM_ACTIVE)); 
+ 			kodicom_setcamera(mbktr, korder[i], i, KODICOM_ACTIVE); 
+ 		}
+ 	    }
+ 	}
+ notkodicom:
  	return 0;
  
  fail:
***************
*** 492,497 ****
--- 565,571 ----
  #ifdef USE_VBIMUTEX
          mtx_destroy(&bktr->vbimutex);
  #endif
+         mtx_destroy(&bktr->kmutex);
  
  	/* Note: We do not free memory for RISC programs, grab buffer, vbi buffers */
  	/* The memory is retained by the bktr_mem module so we can unload and */
***************
*** 844,849 ****
--- 918,942 ----
  	UNLOCK_VBI(bktr);
  
  	return (revents);
+ }
+ 
+ void
+ kodicom_setcamera(struct bktr_softc *m, int device, int camera, int control)
+ {
+ 	int tmp;
+ 	if (device > 4 || camera > 15)
+ 		return;
+ 	tmp = (INL(m, BKTR_GPIO_DATA) & ~0x1ff) | control | (device << 4) |
+ 		camera;
+ 	OUTL(m, BKTR_GPIO_DATA, tmp);
+ }
+ 
+ void
+ kodicom_setgpioen(struct bktr_softc *m)
+ {
+ 	int tmp;
+ 	tmp = INL(m, BKTR_GPIO_OUT_EN) | 0x0003ff;
+ 	OUTL(m, BKTR_GPIO_OUT_EN, tmp);
  }
  
  /*****************/
*** sys/dev/bktr/bktr_reg.h.orig	Fri Sep  1 12:26:48 2006
--- sys/dev/bktr/bktr_reg.h	Tue Jan 30 07:39:55 2007
***************
*** 698,703 ****
--- 698,711 ----
      int			mspsimple;
      int			dolby;
  #endif
+ 
+     struct bktr_softc	*kmaster;
+     unsigned char 	kunit;
+     unsigned char 	kinput;
+     unsigned char 	koutput;
+     #if (__FreeBSD_version >= 500000)
+     struct mtx	kmutex;  /* per card crossbar changing Mutex */
+     #endif
  };
  
  typedef struct bktr_softc bktr_reg_t;
*** sys/dev/bktr/ioctl_bt848.h.orig	Wed Nov 29 14:56:31 2006
--- sys/dev/bktr/ioctl_bt848.h	Wed Nov 29 14:53:36 2006
***************
*** 293,296 ****
--- 293,301 ----
  # define BT848_IFORM_F_NTSCM            (0x1)
  # define BT848_IFORM_F_AUTO             (0x0)
  
+ #define KODICOM_SET_IN		_IOW('x', 76,  unsigned char)
+ #define KODICOM_GET_IN		_IOR('x', 76,  unsigned char)
+ #define KODICOM_SET_OUT		_IOW('x', 77,  unsigned char)
+ #define KODICOM_GET_OUT		_IOR('x', 77,  unsigned char)
+ 
  #endif	/* _DEV_BKTR_IOCTL_BT848_H_ */
*** /dev/null	Wed Nov 29 13:44:00 2006
--- sys/dev/bktr/README.kodicom	Fri Nov 10 07:47:12 2006
***************
*** 0 ****
--- 1,37 ----
+ 
+ The Kodicom 4400 has 4 camera ports on the back of the card and 4 BT878 capture
+ devices. Initially the onboard input crossbar is set to input camera 1 to
+ the first BT878; input camera 2 to the second BT878, etc.
+ 
+ Using the "KODICOM_SET_IN" ioctl(), one can change the input camera for
+ that BT878. An example of switching the camera to input 10:
+ 
+ 	int i;
+ 	unsigned char c;
+ 
+ 	if ((i = open("/dev/bktr0", O_RDONLY)) < 0) {
+ 		printf("open failed\n");
+ 		exit(1);
+ 	}
+ 
+ 	c = 10;	/* valid cameras are 0 to 15 */
+ 
+ 	if (ioctl(i, KODICOM_SET_IN, &c) < 0) {
+ 		printf("setting camera failed: %d\n", errno);
+ 		exit(1);
+ 	}
+ 
+ Using the "KODICOM_SET_OUT" ioctl(), one can change the output camera
+ for the Kodicom card (red RCA jack). Initially, the output port is not
+ active. Any BT878 device on the card can specify the source of the output
+ camera. After an output is specified, the output port remains on. In
+ the future, the API, may use the input value of 255 to turn off the
+ output port. An example of switching the output camera to input 0:
+ 
+ 	c = 0;	/* valid cameras are 0 to 15 */
+ 
+ 	if (ioctl(i, KODICOM_SET_OUT, &c) < 0) {
+ 		printf("setting camera failed: %d\n", errno);
+ 		exit(1);
+ 	}
+ 
