hd audio驱动

hd_audio引脚:
RST(Intel  High Definition Audio Reset): This signal is the master hardware reset to external codec(s).
SYNC(Intel High Definition Audio Sync): This signal is a 48 kHz fixed rate sample sync to the codec(s). It is also used to encode the stream number.
BIT_CLK(Intel High Definition Audio Bit Clock Output):This signal is a 24.000 MHz serial data clock generated by the Intel High Definition 
Audio controller . This signal has an integrated pull-down resistor so that ACZ_BIT_CLK doesn’t float when an Intel High Definition Audio codec 
(or no codec) is connected but the signals are temporarily configured as AC ’97.
DS_OUT(High Definition Audio Serial Data Out):This signal is the serial TDM data output to the codec(s). This serial output is 
double-pumped for a bit rate of 48 Mb/s for Intel High Definition Audio.
SD_IN(High Definition Audio Serial Data In [2:0]): These signals are serial TDM data inputs from the three codecs. The serial 
input is single-pumped for a bit rate of 24 Mb/s for Intel® High Definition Audio. These signals have integrated pull-down resistors 
that are always enabled.
a Buffer Descriptor List (BDL)
GCAP – Global Capabilities 
Command Ring Buffer (CORB) 
Response Inbound Ring Buffer(响应入栈的环形缓冲区) - RIRB
通过一些函数查找源头,找到了module.inc里有它的初始化函数DRIVER_NAME(void);
一.驱动初始化
1.确定pci设备
声卡设备属于pci设备,查看目标板上pci设备信息:pciConfigTopoShow()
找到一个pci相关的设备,本来想看到audio的信息,结果没发现,发现一个可能相关的选项。
然后用pciHeaderShow()查看一下相关信息:
查找到他的版本号和设备号。对应驱动中的id_table中的0x808627d8。所有intel的南桥芯片的设备商号都是8086.
利用pci设备商号和设备号,我们google到了该南桥的型号:Intel Corporation 82801G .
查看内核中含有pci字符的函数,在vxworks shell中执行:lkup "pci"
2.初始化
在DRIVER_NAME()这个初始化函数关键代码如下:
while ((d=id_table[i]) != 0)
{
            //获取pci设备商号和设备号
vendor_id = (d >> 16) & 0xffff;
dev_id = d & 0xffff;
            //从instance=0的顺序号开始查找设备总线号,设备号,功能号并给pcidev赋值,如果找到则创建设备
while (pciFindDevice(vendor_id, dev_id, instance,&bus, &dev, &func) == OK)
{
                        //为pcidev设备申请空间
oss_pci_device_t *pcidev = malloc(sizeof(*pcidev));
                        //创建设备
                        osdev_create ((dev_info_t*)pcidev, DRIVER_TYPE, instance++, DRIVER_NICK,NULL)) ;
                        //将设备绑定到总线上
                        DRIVER_ATTACH (osdev);
}
i++;
}
那么 osdev_create到底做了什么?
#define DRIVER_NICK "oss_hdaudio"
nick是"oss_hdaudio";dip就是包含总线号,设备号和功能的代表设备的结构体pcidev;dev_type是DRV_PCI;instance是设备所在队列的序列号;而handle为NULL。
oss_device_t *
osdev_create (dev_info_t * dip, int dev_type,
      int instance, const char *nick, const char *handle)
{
  oss_device_t *osdev;

  osdev = PMALLOC (NULL, sizeof (*osdev));
  if (osdev == NULL)
    {
      cmn_err (CE_WARN, "osdev_create: Out of memory\n");
      return NULL;
    }

  memset (osdev, 0, sizeof (*osdev));
/*osdev名称osdev->nick='oss_hdaudio0'*/
sprintf (osdev->nick, "%s%d", nick, instance);
/*在链表中的第几个*/
  osdev->instance = instance;
/*pci设备的总线号,设备号,功能号*/
  osdev->dip = dip;
/*设备是否有效*/
  osdev->available = 1;
/*是否有混频器加进去*/
  osdev->first_mixer = -1;
/*modname='oss_hdaudio'*/
  strcpy (osdev->modname, nick);
/*不知道什么作用*/
  if (handle == NULL)
    handle = nick;
/*判断声卡的数目是否超过系统最大能支持的*/
  if (oss_num_cards >= MAX_CARDS)
    cmn_err (CE_WARN, "Too many OSS devices. At most %d permitted.\n",
     MAX_CARDS);
  else
    {
    /*cardnum是导入驱动时的顺序号,用全局变量cards来保存osdev*/
      osdev->cardnum = oss_num_cards;
      cards[oss_num_cards++] = osdev;
    }
/* Create the device handle*/
strcpy(osdev->handle, "PCICARD");

  return osdev;
}
到现在为止,找到了设备并得到了总线号,设备号,功能号,并初始化了pcidev和osdev。
3.下面这个是我加上去的
void audioInit()
{
//设置系统每秒产生1000个时间片
sysClkRateSet(1000);
ossDrv();
}
int ossDrv (void)
{
  //获取每秒产生时间片的数量
  oss_hz = sysClkRateGet();
//导入系统驱动,返回驱动号
  oss_driver_num = iosDrvInstall ((FUNCPTR) NULL,/* create */
  (FUNCPTR) NULL,/* delete */
  (FUNCPTR) ossOpen, (FUNCPTR) ossClose, (FUNCPTR) ossRead, (FUNCPTR) ossWrite, (FUNCPTR) ossIoctl/* ioctl */
    );
/***********************************************************
//和DRIVER_INIT函数里一样,只是有两处不同
1./*osdev名称osdev->nick='osscore0'*/
sprintf (osdev->nick, "%s%d", nick, instance);
2./*modname='osscore'*/
  strcpy (osdev->modname, nick);
**********************************************************/
  core_osdev =osdev_create (NULL, DRV_UNKNOWN, 0, "osscore", NULL);
 /*strcpy (osdev->name, name);只是将core_osdev的name设置为OSS core services*/
  oss_register_device (core_osdev, "OSS core services");
  oss_common_init (core_osdev);
}
再看看oss_common_init (core_osdev);这个函数创建了几个设备,我们来看下
void
oss_common_init (oss_device_t * osdev)
{
  static int drivers_loaded = 0;
  if (drivers_loaded) return;
  drivers_loaded = 1;
  /*只是创建了一个锁*/
  MUTEX_INIT (osdev, audio_global_mutex, MH_DRV); 
  install_vdsp (osdev);
  install_vmidi (osdev);
  install_dev_mixer (osdev);
/*Check that the processor is compatible with vmix (has proper FP support).这个函数用到内嵌汇编和CPUID指令*/
  vmix_core_init (osdev);
}
void
install_vdsp (oss_device_t * osdev)
{
/*void oss_install_chrdev (oss_device_t * osdev, char *name, int dev_class,
    int instance, oss_cdev_drv_t * drv, int flags)
osdev就是我们传进来的core_osdev,name="/dev/dsp",dev_class=OSS_DEV_VDSP,instance=0,最后的flag为CHDEV_VIRTUAL;
其中的drv就是我们的static oss_cdev_drv_t vdsp_cdev_drv = {
  oss_open_vdsp,
  oss_audio_release,
  oss_audio_read,
  oss_audio_write,
  oss_audio_ioctl,
};函数列表*/
  oss_install_chrdev (osdev, "/dev/dsp", OSS_DEV_VDSP, 0, &vdsp_cdev_drv,
      CHDEV_VIRTUAL);
}
void oss_install_chrdev (oss_device_t * osdev, char *name, int dev_class,
    int instance, oss_cdev_drv_t * drv, int flags)
{
  int num;
  oss_cdev_t *cdev = NULL;
  if (oss_num_cdevs >= OSS_MAX_CDEVS)
      grow_array(osdev, &oss_cdevs, &oss_max_cdevs, 100);
  num = oss_num_cdevs++;
  cdev->dev_class = dev_class;
  cdev->instance = instance;
  cdev->d = drv;
  cdev->osdev = osdev;
  strncpy (cdev->name, name, sizeof (cdev->name));
  cdev->name[sizeof (cdev->name) - 1] = 0;
  oss_cdevs[num] = cdev;
  strcpy (cdev->name, name);
  register_chrdev (cdev, name);
}
static void register_chrdev(oss_cdev_t *cdev, char *name)
{
    iosDevAdd ((void *)cdev, name, oss_driver_num) ;
}
就是在设备号上添加一个设备。其他创建过程类似,分别创建了dsp,midi,mixer;
最后vmix_core_init (osdev);判断是否有vmix能力,如果没有就报错。
3.oss_hdaudio_attach(osdev)
在DRIVER_NAME()函数中调用了DRIVER_ATTACH()调用oss_hdaudio_attach();该函数完成了读取pci配置空间,并赋给osdev
int oss_hdaudio_attach (oss_device_t * osdev)
{
    //读取设备商号和设备号
  pci_read_config_word (osdev, PCI_VENDOR_ID, &vendor);
  pci_read_config_word (osdev, PCI_DEVICE_ID, &device);
    //读取pci版本号,命令空间,中断线号,子系统号和子系统
  pci_read_config_byte (osdev, PCI_REVISION_ID, &pci_revision);
  pci_read_config_word (osdev, PCI_COMMAND, &pci_command);
  pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line);
  pci_read_config_word (osdev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
  pci_read_config_word (osdev, PCI_SUBSYSTEM_ID, &subdevice);
  devc->osdev = osdev;
  osdev->devc = devc;
  devc->first_dev = -1;

  devc->vendor_id = (vendor << 16) | device;
  devc->subvendor_id = (subvendor << 16) | subdevice;

  oss_pci_byteswap (osdev, 1);

  switch (device)
    {
    case INTEL_DEVICE_ICH7:
      devc->chip_name = "Intel HD Audio";
      break;
    }
    //读取pci内存基地址
  pci_read_config_dword (osdev, PCI_MEM_BASE_ADDRESS_0, &devc->membar_addr);
  devc->membar_addr &= ~7;
  /* get virtual address */映射虚拟地址
  devc->azbar =(void *) MAP_PCI_MEM (devc->osdev, 0, devc->membar_addr, 16 * 1024);
  devc->irq = pci_irq_line;
  /* activate the device */
  pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
    //写入pci command
  pci_write_config_word (osdev, PCI_COMMAND, pci_command);
  oss_register_device (osdev, devc->chip_name);
    //读取配置空间中的中断号并使能中断
  oss_register_interrupts (devc->osdev, 0, hdaintr, NULL);
  devc->base = devc->membar_addr;

  /* Setup the TCSEL register. Don't do this with ATI chipsets. */
  if (vendor != ATI_VENDOR_ID)
    {
      pci_read_config_byte (osdev, 0x44, &btmp);
      pci_write_config_byte (osdev, 0x44, btmp & 0xf8);
     }
  err = init_HDA (devc);
}
其实就是读取配置空间,填充devc;
int pci_read_config_word   (oss_device_t * osdev, offset_t where, unsigned short *val)
{
return oss_pci_read_config_word(osdev,where,val);
}
int oss_pci_write_config_word (oss_device_t * osdev, offset_t where,unsigned short val)
{
  oss_pci_device_t *pd = osdev->dip;
  return pciConfigOutWord (pd->bus, pd->dev, pd->func, where, val);
}
4.初始化hd_audio的init_HDA()
static int init_HDA (hda_devc_t * devc)
{
  /* Reset controller */
 reset_controller (devc);
  PCI_WRITEL (devc->osdev, devc->azbar + HDA_INTCTL, PCI_READL (devc->osdev, devc->azbar + HDA_INTCTL) | 0xc0000000);/* Intr enable */
  /*Set CORB(Command Outbound Ring Buffer) and RIRB(Response Inbound Ring Buffer) sizes to 256, 16 or 2 entries(条目).设置命令
输出循环buffer和响应入栈的环形缓冲区的条目数  */
  tmp = (PCI_READB (devc->osdev, devc->azbar + HDA_CORBSIZE) >> 4) & 0x07;
  if (tmp & 0x4) /* 256 entries */
    PCI_WRITEB (devc->osdev, devc->azbar + HDA_CORBSIZE, 0x2);
  else if (tmp & 0x2) /* 16 entries */
    PCI_WRITEB (devc->osdev, devc->azbar + HDA_CORBSIZE, 0x1);
  else /* Assume that 2 entries is supported */
    PCI_WRITEB (devc->osdev, devc->azbar + HDA_CORBSIZE, 0x0);

  tmp = (PCI_READB (devc->osdev, devc->azbar + HDA_RIRBSIZE) >> 4) & 0x07;
  if (tmp & 0x4) /* 256 entries */
    PCI_WRITEB (devc->osdev, devc->azbar + HDA_RIRBSIZE, 0x2);
  else if (tmp & 0x2) /* 16 entries */
    PCI_WRITEB (devc->osdev, devc->azbar + HDA_RIRBSIZE, 0x1);
  else /* Assume that 2 entries is supported */
    PCI_WRITEB (devc->osdev, devc->azbar + HDA_RIRBSIZE, 0x0);

  /* setup the CORB/RIRB structs :(1)Allocate the CORB and RIRB buffers.(2) Initialize CORB and RIRBregisters*/
    setup_controller (devc);
  /* setup the engine structs 初始化输入输出引擎(两个引擎对应下面的两个输入和输出设备)*/
  setup_engines (devc);
    //创建混频器设备,混频器提供随意混合使用多个通道(来源)的设施,其中还初始化了codec
    devc->mixer = hdaudio_mixer_create (devc->chip_name, devc, devc->osdev,
do_corb_write, corb_read,
devc->codecmask, devc->vendor_id,
devc->subvendor_id);
    //将混频器设备给devc
  devc->mixer_dev = hdaudio_mixer_get_mixdev (devc->mixer);
    //读取全局能力寄存器
  gcap = PCI_READW (devc->osdev, devc->azbar + HDA_GCAP);
//在这里,注册两个字符设备设置字符设备的各个函数接口
  install_outputdevs (devc);
  install_inputdevs (devc);
  activate_vmix (devc);
}
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章