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);
}
 

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