(본 글의 모든 저작권은 하제소프트가 가지고 있습니다)

USB 호스트 컨트롤러 드라이버

리눅스는 UHCI, OHCI, EHCI 그리고 xHCI 모두를 지원하고 있다. 개발자가 직접 USB 호스트 컨트롤러 드라이버를 만드는 일은 거의 없지만, 가상 USB 솔루션(USB over IP 또는 MAUSB)등을 개발하려는 경우 호스트 컨트롤러 드라이버를 작성할 줄 알아야 한다.

리눅스의 허브드라이버는 외장허브를 직접 관리하고 루트허브에 대해서만 일부 호스트 컨트롤러 드라이버의 도움을 요청한다.

열거과정을 통해 USB 호스트 컨트롤러 드라이버 동작을 이해하기

USB 호스트 컨트롤러 드라이버가 동작하는 모습을 이해하기 쉽도록 이번 절에서는 그림을 통해서 호스트 컨트롤러부터 루트허브의 포트를 거쳐, 새로운 디바이스가 발견되는 과정까지의 흐름을 확인해보도록 한다.

호스트컨트롤러 하드웨어를 준비하는 과정

12-3

호스트컨트롤러로 사용되는 하드웨어가 버스 드라이버에 의해서 열거되면, 호스트 컨트롤러 드라이버로 사용되고자 하는 드라이버는 자신의 vhci_probe()함수를 준비한다.

vhci_probe()함수는 usb_create_hcd()함수를 호출해서 등록할 hcd 자료구조를 준비한다. 이어서 usb_add_hcd()함수를 호출해서 준비된 hcd를 등록한다.

루트허브를 열거하는 과정

12-4

vhci_probe()함수에서 호출하는 usb_add_hcd 함수는 아직 리턴되지 않는다. 이 함수는 호스트 컨트롤러를 등록하는 과정중에 호스트 컨트롤러가 제공하는 루트허브에 대한 정보를 획득하기 위해서 호스트 컨트롤러 드라이버의 콜백함수를 호출한다.

호스트 컨트롤러 드라이버가 제공하는 콜백함수중에 vhci_hub_control 함수와 vhci_hub_status 함수는 루트허브와 관련된 작업을 지원하는 함수이다.

그림을 보면, BOS 디스크립터와 허브 디스크립터를 제공하는 콜백함수를 알 수 있다. 허브 디스크립터를 통해서 제공하는 정보에는 허브가 가지는 Downstream Port의 개수정보가 있다. 이들의 개수만큼 각각의 포트에 전원을 공급하라는 의미로 ‘SET_PORT_FEATURE(POWER)’ 명령이 포트마다 전달된다.

포트에 연결된 새로운 디바이스 발견 및 열거과정

호스트 컨트롤러는 루트허브를 가지고 있다. 루트허브가 가지는 Downstream Port USB 3 USB 2에 따라서 각각 상태머쉰을 유지해야 한다. 이와 같은 상태머쉰을 유지하기 위해서 허브드라이버는 각각의 포트를 대상으로 Feature 기능을 사용하면서 루트허브를 위한 호스트 컨트롤러 드라이버를 사용한다.

여기서는 루트허브중에서 첫번째 허브 Downstream 포트(#1)에 새로운 디바이스가 연결되었다는것을 가정해보도록 한다.

이와 같이 포트에 새로운 디바이스가 연결되는 상황은 동적으로 발생되는 사건이다. 이와 같은 사건이 발생할 때 마다 호스트 컨트롤러 드라이버는 usb_hcd_poll_rh_status 함수를 호출한다. 이 함수는 루트허브의 포트의 상태가 변경되었음을 루트허브드라이버에게 알리는 역할을 수행한다.

지금은 이와 같은 상황과 다르게, 처음 루트허브의 포트가 열거되는 과정중에 이미 새로운 디바이스가 포트에 연결되어 있는 상황을 가정하도록 한다.

루트허브의 특정 포트에 새로운 디바이스가 연결되는 상황

12-5

루트허브포트에 새로운 디바이스가 연결되는 상황이다. 앞서서 언급했듯이 이와 같은 상황이 동적으로 발생될때는 호스트 컨트롤러 드라이버는 usb_hcd_poll_rh_status 함수를 호출해야 한다. 그러면, 이어서 호스트 컨트롤러 드라이버의 hub_status_data 콜백함수가 호출된다. 이 함수는 루트허브가 가지고 있는 모든 포트의 변화상태를 비트맵형태로 보고한다. 이와 같이 보고되는 내용이 있다면, 이어서 [그림 12-5]와 같은 상황이 된다. 지금 그림은 루트허브의 포트가 열거되는 과정중에 새로운 디바이스의 연결상태를 감지하는 상황이다.

허브 드라이버는 루트허브와 외장허브모두를 관리한다. 이중에서 루트허브에 대해서는 허브포트의 상태머쉰을 유지하는 작업을 위해서 호스트컨트롤러드라이버의 콜백함수를 사용한다.

1) 각각의 포트를 조사한다. 현재 시나리오에서는 첫번째 포트에 대해서 포트상태를 정의하고 있다. 현재 포트의 디바이스가 연결되었다는 정보를 주고 있다.

2) 변경된 정보를 클리어하도록 요청하고 있다.

3) 새로운 디바이스를 위한 자원을 할당하도록 요청한다. xHCI 호스트컨트롤러의 경우, Device Slot 을 할당하는 작업을 이곳에서 수행한다.

4) 포트의 상태를 확인하고 있다. 허브 드라이버가 원하는 Link State 상태를 확인한다. 현재 USB 3 허브를 가정하고 있기 때문에, USB 3 에서 소개하는 LTSSM(Link Training Status State Machine) 12단계의 상태값을 확인한다.

5) 포트의 상태변경사건을 지운다.

6) 새롭게 발견된 디바이스로부터 디스크립터를 읽거나 주소를 지정하는 작업을 위한 URB를 전송한다.

호스트 컨트롤러 드라이버가 성공적으로 URB를 다루게 되면, 이어서 새롭게 발견된 디바이스를 위한 호스트 클라이언트 드라이버가 제어권을 넘겨받게 된다. 이후, URB요청만 반복으로 내려오게 될것이다.