iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0

昨天簡單介紹如何存取環控晶片暫存器後,今天就把概念轉換為函式實作,一樣是暫時將函式實作在Non-Pnp驅動程式範例裡的測試程式。

  • testapp.c
    • 讀寫I/O埠
      • 兩個函式都會使用到DeviceIoControl,將對應的I/O control code傳到指定的裝置,使指定的裝置執行對應的函式,詳細參數內容可以自行閱讀參考內容。
      • 使用IO_PORT_INPUT作為input buffer,傳遞I/O埠號和寫入I/O埠的資料。
      • Output buffer則是用unsigned char所宣告的變數傳入,因為我們的回傳值都是一個byte。
      • bytesReturned則是用來承接回傳的長度。
      nsigned char ReadIoPort(
      HANDLE hDevice,
      unsigned int Index
      )
      
      BOOL Result = FALSE;
      unsigned char Output;
      unsigned long bytesReturned;
      IO_PORT_INPUT Input;
      
      Input.PortNumber = Index;
      Result = DeviceIoControl(hDevice,
      	(DWORD)IOCTL_CUSTOM_READ_IO_COMMAND,
      	&Input,
      	sizeof(Input),
      	&Output,
      	sizeof(Output),
      	&bytesReturned,
      	NULL
      );
      
      return Output;
      
      ``
      
      ``c
      OOL WriteIoPort(
      HANDLE hDevice,
      unsigned int Index,
      unsigned int Data
      )
      
      BOOL Result = FALSE;
      IO_PORT_INPUT Input;
      unsigned char Output;
      
      Input.PortNumber = Index;
      Input.IoPortData.CharData = (unsigned char)Data;
      Result = DeviceIoControl(hDevice,
      	(DWORD)IOCTL_CUSTOM_WRITE_IO_COMMAND,
      	&Input,
      	sizeof(Input),
      	&Output,
      	sizeof(Output),
      	NULL,
      	NULL
      );
      
      return Result;
      
      ``
      
      
    • 進入和離開Extended Function Mode的實作,可以看到進入時依照文件填入2次0x87,離開時填入0xAA。
      oid OpenSioConfig(HANDLE hDevice)
      
      unsigned int Index = SIO_INDEX_PORT;
      
      printf("OpenSioConfig\n");
      WriteIoPort(hDevice, Index, 0x87);
      WriteIoPort(hDevice, Index, 0x87);
      return;
      
      ``
      
      ``c
      oid CloseSioConfig(HANDLE hDevice)
      
      unsigned int Index = SIO_INDEX_PORT;
      
      printf("CloseSioConfig\n");
      WriteIoPort(hDevice, Index, 0xAA);
      return;
      
      ``
      
      
    • 讀寫環控晶片暫存器的實作
      • Day12所提,要讀取環控晶片暫存器的值,是對Index埠寫入暫存器位置,Data埠會回傳該暫存器位置的值
      • 若要寫入值到環控晶片暫存器,則是對Index埠寫入暫存器位置,再對Data埠寫入所指定的值
      nsigned char ReadSio(
      HANDLE hDevice,
      unsigned int Index
      )
      
      unsigned int IndexPort = SIO_INDEX_PORT;
      unsigned int DataPort = SIO_DATA_PORT;
      unsigned char Output;
      
      WriteIoPort(hDevice, IndexPort, Index);
      Output = ReadIoPort(hDevice, DataPort);
      return Output;
      
      ``
      
      ``c
      OID WriteSio(
      HANDLE hDevice,
      unsigned int Index,
      unsigned int Data
      )
      
      unsigned int IndexPort = SIO_INDEX_PORT;
      unsigned int DataPort = SIO_DATA_PORT;
      BOOL Result = FALSE;
      
      Result = WriteIoPort(hDevice, IndexPort, Index);
      Result = WriteIoPort(hDevice, DataPort, Data);
      return;
      
      ``
      
      
    • 最後測試存取環控晶片的測試函式,我們將測試函式放在DoIoctls後。
      • Day12所講,環控晶片的暫存器是以logical device的形式存在,這裡我們試著讀取logical device D,暫存器位置0x30的值。
      • 首先呼叫OpenSioConfig進入Extended Function Mode。
      • 再將0x0D寫入全域暫存器0x07,切換到logical device D。
      • 然後讀取暫存器位置0x30的值並印出。
      • 結束操作後呼叫CloseSioConfig離開Extended Function Mode。
      OID
      oIoPortTest(
      HANDLE hDevice
      )
      
      unsigned char res;
      
      printf("\nDoIoPortTest\n");
      OpenSioConfig(hDevice);
      WriteSio(hDevice, 0x07, 0x0D);
      res = ReadSio(hDevice, 0x30);
      printf("SIO read result: 0x%2X\n", res);
      CloseSioConfig(hDevice);
      printf("\n");
      
      return;
      
      
      ``
      
      

以上函式連同Day11驅動程式的部分加入Non-Pnp driver sample後,重新編譯Non-Pnp driver sample,依照Day08的步驟執行nonpnpapp.exe會得到以下畫面,可以看到DoIoPortTest有成功讀取到logical device D,暫存器位置0x30的值,讀出的數值為0xA0。

為了正確性,使用第三方軟體RW來驗證,一樣切換到logical device D,可以看到暫存器位置0x30的值與測試程式結果一致,測試成功。

參考內容

環控晶片 - NCT6796D
DeviceIoControl
RWEverything


上一篇
Day12 使用I/O存取環控晶片-2
下一篇
Day14 使用I/O存取環控晶片-4
系列文
Windows Driver + Electron 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言