|
NetBSD 문서:커널 프로그래밍 문답 |
options DDB'이 설정되어 있는지 확인
해 주십시오. 파일에 '#include "opt_ddb.h"'를 포함하고
'Debugger()'를 사용하면 됩니다.
xxxattach() 이 루틴은 장치를 설정하고 장치에 접속합니다.probe와 attach 루틴을 쓰려면
/usr/src/sys/arch/<your-arch>/<your-arch>/conf.c에 엔트리를 추가해 주십시오.
아래에 두개의 테이블이 있습니다:
cdevsw 문자 장치용.bdevsw 블록 장치용. ("블록" I/O와 장치를 이끄는 루틴으로
사용 합니다.)
대부분의 엔트리는 cdev_xxx_init()라고 하는 형식이 됩니다.
이것은 표준 Unix 장치 스위치 루틴의 프로토타입을 위한 매크로입니다.
probe와 attach 루틴은 부팅 할때 호출 됩니다.
open(), close(), read(),
write() 루틴은 주 번호와 테이블 인덱스가 일치하는 장치
파일이 열렸을 때 호출 됩니다. 예를 들면 cdevsw[]/bdevsw
안의 장치 번호 18의 "open" 루틴이 호출 됩니다.
대부분 드라이버는 버스의 고유 attach 코드와 머신 독립적인 코어로 나누어져 있습니다. 예를 들면 PCI lance 이더넷 드라이버는 아래 파일로 구성되어 있습니다:
autoconf 설명 참고.
autoconf의 작동 방식을 이해 한다면 autoconf는 아주 간단합니다. 장치 probe 트리 구축 및 동작의 세부 사항을 무시하고 각각의 "leaf" 드라이버를 위해 필요한 것들은 다음과 같습니다:
struct cfattach foo_baz_ca = {
sizeof(struct foo_baz_softc), foo_baz_match, foo_baz_attach
};
예제: PCI ethernet 장치 'baz'의 커널 설정을 살펴 봅시다. 다음 보기와 같습니다:
pci* at mainbus? baz* at pci? dev ? function ?
autoconf는 물리 장치가 pci 버스에 접속하는 것을 반복 합니다. 각 물리 장치는 pci 버스를 커널 안에 등록 하고 드라이버의 probe 루틴을 호출 합니다. probe 루틴이 1을 리턴 한다면 autoconf는 작업 반복을 멈추고 위의 작업 3)을 실행 합니다. 접속(attach)에서 되돌아 와서 autoconf는 다음 물리 장치에 대한 루틴을 계속합니다.
커널에 새로운 드라이버 추가를 참고하십시오.
참고. NetBSD 1.6과 그 이상에서는 특별한 "vendor" sysctl 카테고리를 가지고 있습니다. 그것들은 vendor 상세 엔트리를 위해 예약되어 있습니다. 자세한 정보는 sysctl(8)을 참고하십시오.
먼저 mmap 인터페이스를 위해서 적당한 오프셋 몇개를 선택해 주십시오. "mmap 오프셋 0-M은 오브젝트 A에게 주고, N-O는 오브젝트 B에게 준다", 기타. 처럼 합니다.
이것이 끝나면 mmap 루틴은 다음과 같습니다:
int
foommap(dev, off, prot)
dev_t dev;
int off, prot;
{
if (off & PAGE_MASK)
panic("foommap");
if ((u_int)off >= FOO_REGION1_MMAP_OFFSET &&
(u_int)off < (FOO_REGION1_MMAP_OFFSET + FOO_REGION1_SIZE))
return (atop(FOO_REGION1_ADDR + ((u_int)off -
FOO_REGION1_MMAP_OFFSET)));
if ((u_int)off >= FOO_REGION2_MMAP_OFFSET &&
(u_int)off < (FOO_REGION2_MMAP_OFFSET + FOO_REGION2_SIZE))
return (atop(FOO_REGION1_ADDR + ((u_int)off -
FOO_REGION2_MMAP_OFFSET)));
/* Page not found. */
return (-1);
}
그런데, 실제로 단순한 커널 메모리 오브젝트를 mmap 하므로 코드는 좀 더 복잡하게 됩니다.(결국 가상 장치(pesudo-device)이기 때문입니다.)
이것을 동작시키기 위해서는 할당한 메모리 오브젝트를 페이지된 경계에 확실히 mmap 해야 합니다. 만약 할당한 메모리 크기 >= PAGE_SIZE 라면 괜찮지만, 그렇지 않으면 uvm_km_alloc()를 사용해 할당 크기를 페이지 크기에 맞게 해주십시오.
약간 수정한 것은 다음과 같습니다:
int
foommap(dev, off, prot)
dev_t dev;
int off, prot;
{
paddr_t pa;
if (off & PAGE_MASK)
panic("foommap: offset not page aligned");
if ((u_int)off >= FOO_REGION1_MMAP_OFFSET &&
(u_int)off < (FOO_REGION1_MMAP_OFFSET + FOO_REGION1_SIZE)) {
if ((vaddr_t)foo_object1 & PAGE_MASK)
panic("foommap: foo_object1 not page aligned");
if (pmap_extract(pmap_kernel(), foo_object1 +
(u_int)off - FOO_REGION1_MMAP_OFFSET, &pa) == FALSE)
panic("foommap: foo_object1 page not mapped");
return (atop(pa));
}
if ((u_int)off >= FOO_REGION2_MMAP_OFFSET &&
(u_int)off < (FOO_REGION2_MMAP_OFFSET + FOO_REGION2_SIZE)) {
if ((vaddr_t)foo_object2 & PAGE_MASK)
panic("foommap: foo_object2 not page aligned");
if (pmap_extract(pmap_kernel(), foo_object2 +
(u_int)off - FOO_REGION2_MMAP_OFFSET, &pa) == FALSE)
panic("foommap: foo_object2 page not mapped");
return (atop(pa));
}
/* Page not found. */
return (-1);
}
|
|