Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 6 Oct 1996 21:51:23 -0500 (CDT)
From:      Eduardo Viruena Silva <mrspock@esfm.ipn.mx>
To:        hackers@freebsd.org
Subject:   OPTi MAD16 Sound Card and CD-Interface. 
Message-ID:  <Pine.BSF.3.91.961006214803.6016C-100000@Michelle.esfm.ipn.mx>

next in thread | raw e-mail | index | archive | help

Hello again!

I have detected some problems while using OPTi's Mad16 Sound Card
interface for controlling CD-ROM drivers.  I own a Sony CDU33A Rev 1.0f
and my kernel is unable to see it if it is controlled by my OPTi card.


I have been told to use:

		options "OPTI_MAD16_PORT" 

to build my kernel. It did not work.  Nevertheless, using this option or
not, if my computer was started under MS-DOS, the sound card was, somehow,
initialized correctly and if I reboot my computer (ctrl-alt-del) and make
it load FreeBSD, FreeBSD see my CD-Driver correctly. 

My OPTi MAD16 card is based in the OPTi 82c930 chip.  According to OPTi 
documentation in http://www.opti.com, this chip has three important 
registers in ports 0xF8F, 0xE0E and 0xE0F.

Register in port 0xF8F is important.  The first thing you have to do is 
write 0xE4 (password) in this register.  Doing this, you are allowed to 
manipulate the registers of the OPTi card.

Then there is another register in port 0xE0E, in which you have to write
an index to access different parts of the card:  CD-interface,
MIDI-interface, etc. 

Register in port 0xE0F lets you read and write the register specified by 
index in 0xE0F.

According to documentation in "http://www.opti.com" the register with index 
"2" (called MC2) is used to control the CD-interface.  But, OPTi's 
documentation is not complete!!

There is a MS-DOS driver that initializes the card correctly: 
CDSETUP.SYS.  I disassembled this drive and I learned some important facts
of register MC2: 

MC2 register options can be summarized in this table:

	bit   7 6 5 4 3 2 1 0
              b b m i i i d d

	b b   specifies the iobase for cd-interface:

		0 0 =  iobase 0x340
		0 1 =  iobase 0x330
		1 0 =  iobase 0x360
		1 1 =  iobase 0x320      opti's documentation ends here.

	m     specifies if the ide interface is using a dma channel.

		0 = ide dma diasbled
		1 = ide dma enabled


	i i i specifies the irq level used by the cd-interface.

		0 0 0 = irq disabled
		0 0 1 = irq  5
		0 1 0 = irq  7
		1 0 0 = irq  9
		1 0 1 = irq 10
		1 1 0 = irq 11
		
	d d   specifies the dma channel used bye the cd-interface.		

		0 0 = dma disabled
		1 1 = dma channel 3


If you are interested, I have "the source code" for this MS-DOS driver. 
Please let me know if you need it... (This program belongs to OPTi, and I
don't like to be envolved in legal problems, please continue reading, you
will find my C equivalent). 

This driver is rather dirty programmed. You know, machine code for C 
programs is easy to hack.  This program seems to have been done with a 
hammer and brute force.

I corrected my FreeBSD kernel for initializing my OPTi card.
I'm tired of hacking, so I made something very dirty but functional... 


There is a file called:

		/usr/src/sys/i386/isa/scd.c

And there, in line #689 there is a function "scd_probe".  Just before 
this lines I included my code for OPTi (in the lines above) inserting the 
lines:

/*------------[before scd_probe]------------------------*/
#ifdef OPTI_MAD16_PORT
#   include "opti.c"
#endif
/*------------------------------------------------------*/


And a few lines below, just before label "again:"  I inserted these lines:


/*-------------[before label "again:"] ---------------------------*/
#ifdef OPTI_MAD16_PORT
        OPTi_cd_init(1,dev->id_iobase,dev->id_irq,dev->id_drq);
#endif
/*----------------------------------------------------------------*/


Then I created the file:  "/usr/src/sys/i386/isa/opti.c"
with the lines at the end of my e-mail.


I still have a lot of questions:

	1) Where "inb" and "outb" are defined ?   Where are their
	   prototypes ?

	2) This code must be "factorized" in such a way that "ide", 
	   "mitsumi" and "panasonic" drivers can use it.  Does anybody
	   know how to do this ?

	3) If I'd want to study the FreeBSD kernel... Is there a reference 
	   for knowing how it is organized ?

I hope this work can be useful for the FreeBSD friends and lovers.
Could you preseve my name and e-mail address in my source code ?
	If not, may a lighting part you in two.




  /\  /\             _ 
 /  \/  \       \___/_\          __
 ( O O _)          /            / /
  \   /\          /    ___     / /   ___
   | |\          /    /   |   / /   / |_|_
    O         __/____/\__/\___|/___/\__/
              \/

------------------[ /usr/src/sys/i386/isa/opti.c ]-------------------

#ifndef OPTI_C
#define OPTI_C

/*
	This code is a gift for FreeBSD, and of course, it may make your
	computer explode, therefore, I'm not responsable for whatever
	happens to your computer for using it...

						Eduardo Viruena.
						mrspock@esfm.ipn.mx
						Oct 6th, 1996
*/


/* this function writes the OPTi card password and disable protection */

static void OPTi_pw( void )
 {
   /*  here it is necessary to disable interrupts*/
   outb( 0xF8F, 0xE4 );
   outb( 0xF8F, 0x80 );
   /*  here it is necessary to enable interrupts*/
 }


/* this function reads register "reg" */

static int OPTi_rd( int reg )
 {
   /*  here it may be necessary to disable interrupts*/
   outb( 0xF8F, 0x80 );
   outb( 0xE0E, reg );
   /*  here it is necessary to enable interrupts*/
   return inb( 0xE0F );
 }

/* this function writes "val" to register "reg" */

static int OPTi_wr( int reg, int val )
 {
   /*  here it may be necessary to disable interrupts */
   outb( 0xF8F, 0x80 );
   outb( 0xE0E, reg );
   outb( 0xE0F, val );
   /*  here it is necessary to enable interrupts*/
   return 0;
 }


/*
According to MS-DOS driver, there is a way to know if the OPTi card is 
present, namely:
*/

int OPTi_present(void)
  {
   int tmp;

   OPTi_pw();
   tmp= OPTi_rd(7);

   OPTi_wr(7,0xCB);
   if (OPTi_rd(7) == 0xCB )
     {
      OPTi_wr(7,tmp);
      return 1;              /*  card is present */
     }
   return 0;
  }


/*
Next function selects the interface you want to use

	cd= 0   no CD	  
          = 1   mitsumi CD
	  = 2   Sony CD
          = 3   panasonic CD
	  = 4   IDE CD  (atapi?)  I do not know, I don't have one...   
*/


int OPTi_cd_type( int cd )
  {
   int tmp= OPTi_rd(1) & 0xF1;

   switch ( cd )
     {
      case 0: tmp |= 0x06;      /* no cd        */
              break;
      case 1: tmp |= 0x02;      /* mitsumi cd   */
              break;
      case 2: tmp |= 0x04;      /* sony cd      */
              break;
      case 3: tmp |= 0x00;      /* panasonic cd */
              break;
      case 4: tmp |= 0x0E;      /* ide cd (atapi?) */
              OPTi_wr(2,OPTi_rd(2) & 0x20);
              break;
     }

   return OPTi_wr(1,tmp);
  }


/*
Next function selects the iobase you want to use, valid values are:
	0x320, 0x330, 0x340, 0x360
*/


int OPTi_cd_port( int ioaddr )
  {
   int tmp= OPTi_rd(2) & 0x3F;

   switch( ioaddr )
     {
      case 0x320: tmp |= 0xC0;
                  break;

      case 0x330: tmp |= 0x40;
                  break;

      case 0x340: tmp |= 0x00;
                  break;

      case 0x360: tmp |= 0x80;
                  break;
     }

   return OPTi_wr(2,tmp);
  }

/*
Next function selects the irq you want to use, valid values are:
	0 (no irq), 5, 7, 9, 10, 11
*/

int OPTi_cd_irq( int irq )
  {
   int tmp= OPTi_rd(2) & 0xe3;

   switch (irq)
     {
      case 0:  tmp |= 0x00;       /* irq disable */
               break;
      case 5:  tmp |= 0x04;       /* irq  5 */
               break;
      case 7:  tmp |= 0x08;       /* irq  7 */
               break;
      case 9:  tmp |= 0x10;       /* irq  9 */
               break;
      case 10: tmp |= 0x14;       /* irq 10 */
               break;
      case 11: tmp |= 0x18;       /* irq 11 */
               break;
     }

   return OPTi_wr(2,tmp);
  }

/*
Next function selects the dma channel you want to use, valid values are:
	0 (no dma), 3
*/

int OPTi_cd_dma( int dma )
  {
   int tmp= OPTi_rd(2) & 0xFC;

   switch (dma)
     {
      case 0: tmp |= 0x00;    /* disable dma */
              break;
      case 1:                 /*  ???  */
              break;
      case 2:                 /*  ???  */
              break;
      case 3: tmp |= 0x03;    /* channel 3 */
              break;
     }

   return OPTi_wr(2,tmp);
  }


int OPTi_cd_init( int type, int port, int irq, int dma)
  {
   if (OPTi_present())
     {
      OPTi_cd_type( type );
      OPTi_cd_port( port);
      OPTi_cd_irq( irq );
      OPTi_cd_dma( dma );
      return 0;
     }
   return 1;
  }

#endif

-------------[ End of /usr/src/sys/i386/isa/opti.c ]---------------









Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.91.961006214803.6016C-100000>