리눅스 커널 2.6.14기반 PXA 270 핸들링 ③

개발 환경 Cross Toolchain● 직접 작성한 툴체인을 사용했으며, 각 패키지 별 소스의 버전은 다음과 같다. - binutils-2.15.94.0.2 - glibc-2.3.5- glibc-linuxthreads-2.3.5 - gcc-3.4.4- linux-2.6.14 커널 소스- gdb-6.4● 크로스 컴파일러 : arm-linux-gcc-3.4.4리눅스 커널 버전● linux-2.6.14-rc5 사용● rc3 버전 이상을 사용하지 않으면 보드에서 부팅할 때 포팅이 제대로 되어 있어도 부팅 중에 커널 영역에서 유저 영역으로 넘어갔을 때 elf 파일 형식을 못 찾아서 에러가 발생한다. Host PC● Fedora core 4(linux-2.6.14)Target Board● hybus xhyper255A● hanback empos tiny xhyper255A커널 포팅 과정(기본 설정, 아키텍쳐, 메모리 까지)원하는 버전의 범용 리눅스 소스를 다운● http://www.kernel.org/pub/linux/kernel/패치 적용● 커널 2.4.x 버전- 시스템 코어 패치(arm core) : Russell King이 제작하며 rmk 패치라고 한다. - 아키텍쳐 패치(xscale) : pxa255 패치● 커널 2.6.x 버전- 2.6.x 버전 대는 커널 소스 내부에 이미 arm 포팅을 위한 필요 소스가 포함되어 있기 때문에 특별히 코어 패치와 아키텍처 패치를 해주지 않아도 된다. 본 문서의 적용 타깃 보드는 Hybus Xhyper255A를 예로 들었다.커널 컴파일 설정● Makefile과 Kconfig : 컴파일을 할 때에 추가할 소스가 오브젝트 파일로 커널에 포함되어 같이 컴파일 되도록 설정하기 위해서 이 파일을 수정한다. Makefile은 대부분의 디렉토리에 포함되어 있으며(디렉토리만 존재하는 디렉토리 및 특수한 경우를 제외), 각 디렉토리에 있는 파일의 컴파일 규칙이 정의 되어 있다. ① 컴파일 기본 설정 : 경로 및 파일명(/커널소스/Makefile) : 컴파일 되는 소스의 버전 정보를 수정한다. 이는 포팅 된 커널을 다운 받은 사용자가 어떠한 패치가 되어 있는가 하는 정보를 알 수 있도록 해준다. 보통 먼저 패치 된 패치 정보가 EXTRAVERSION의 왼쪽부터 쓰여 진다. : 컴파일 할 아키텍처를 명시하고 컴파일 할 컴파일러를 설정한다. arm용 커널로 포팅을 하기 위해 ARCH를 arm으로 해주고, 크로스 컴파일러의 접두어를 써준다. 이는 크로스 컴파일러를 사용해서 커널을 컴파일 할 때 사용되는 gcc, ld 등의 컴파일에 필요한 명령어를 사용할 수 있게 해준다. 즉, arm-linux-gcc, arm-linux-ld 등의 커맨드를 사용할 수 있도록 설정하는 것이다.② 보드 종류 구분 상수 추가 : 경로 및 파일명(/커널소스/arch/arm/tools/mach-types) : 이 파일을 열어보면 다음과 같이 800개 이상의 제품이 등록되어 있다. 포팅을 할 때에 이 파일에 등록되어 있는 제품을 쓰면 아키텍처 부분은 포팅 할 필요가 없겠지만 대부분이 그렇지 않기에 이 파일에 임의적으로 타깃 보드를 구분해 줄 번호를 지정해주어야 한다. 항목은 총 4개 이며, 첫 번째는 보드 이름, 두 번째는 아키텍처 구분 명, 세 번째는 아키텍처가 아닌 다른 부분(MTD, CONFIG 등)에 접미어가 될 구분 명, 마지막은 실제 구분될 상수 값이다. 이 부분을 추가해 주어야 코드에서 우리가 사용할 보드를 인식할 수 있게 된다. : 이렇게 사용할 보드를 등록하는 이유는 다음과 같다. 커널 시작점인 head-armv.S는 프로세서 타입을 찾고 아키텍처 타입을 찾고 가장 최초의 MMU 페이지 테이블을 만든다. 즉, 커널이 동작할 때 먼저 검사하는 것이 이 머신 아키텍처 ID이다. 중복된 숫자만 아니면 되기 때문에 아무 숫자나 붙여도 된다. 다만 부트 로더에서는 이 번호를 반드시 지정해서 커널을 호출해야 한다. 커널소스/include/ asm-arm/mach/arch.h의 마지막 부분에 #define MACHINE_START(_type,_name)라고 정의 되고 이는 커널소스/arch/arm/mach-pxa/xhyper255.c의 MACHINE _START(XHYPER255, "Hybus PXA25x Development Platform") 에서 호출하게 된다.③ 커널 압축 해제 후 아키텍처 비교 설정 : 경로 및 파일명(/커널소스/arch/arm/boot/compressed/ head-xscale.S) : 커널을 컴파일 하면 나오는 zImage는 두 부분으로 나누어져 있다. 먼저 head이다. 이 부분은 압축된 커널 이미지에 대한 압축 정보를 담고 있으며 이 정보로 커널의 압축을 풀게 된다. 그리고 나머지 부분은 커널의 실제 이미지인 piggy.o이다. 실제로 압축되어 있는 커널의 이미지이다. 여기서는 head가 수행될 때 현재 아키텍처의 컴파일 설정이 xscale로 되어 있기 때문에 head-xscale.S로 접근하게 되며 이 파일에 나온 아키텍처 타입과 실제 커널의 아키텍처 타입을 맞추어 주어야 한다. 이 부분이 안 맞으면 부팅이 되지 않는다. 아래 부분을 파일에 추가해 주어야 한다. 커널 컴파일 설정에서 선택한 아키텍처 타입이 MACH_ XHYPER255A로 되어 있음을 명시해 주어야 부팅이 된다.④ 아키텍처 메뉴 추가 : 경로 및 파일명(/커널소스/arch/arm/mach-pxa/Kconfig) (/커널소스/arch/arm/mach-pxa/Makefile) : 원하는 메뉴를 추가하기 위해서는 추가를 원하는 파일이 있는 디렉토리의 Kconfig(커널 2.6버전) 파일과 (커널 2.4버전은 Config.in 파일) Makefile 파일을 같이 수정해 주어야 한다. 이 때 수정해야 할 파일의 경로를 선택해야 하는데 이는 포팅 할 타깃 보드의 스펙에 따라서 달라지며, 본 문서에서는 arm용 pxa로 컴파일을 하기 때문에 arm 디렉토리의 mach-pxa 경로를 선택한다. 커널 소스의 arch라는 디렉토리에는 현재 커널에서 지원되는 많은 종류의 아키텍처들이 포함되어 있다. 이 경로의 의미를 살펴보면, arch는 아키텍처 분류 디렉토리를 의미하고, arm은 시스템 코어 타입을 뜻하며, mach-pxa는 아키텍처의 종류를 나타낸다. - Kconfig 수정 : 경로 및 파일명(/커널소스/arch/arm/mach-pxa/Kconfig) : 이 파일에 다음 스크립트를 추가함으로서 컴파일 메뉴의 System type에서 아키텍처를 설정하도록 만든다. 스크립트를 보면 bool 옆의 “Hybus Xhyper255A Devel- opment Platform”이라는 문구가 메뉴에 보이게 되며 이를 메뉴에서 선택하면 컴파일을 할 때 MACH_XHYPER255A, MACH_XHYPER255, PXA25x 이 세 가지 값을 시스템 타입으로 인식하여 컴파일을 수행한다. : 아래의 스크립트는 MACH_XHYPER255의 값을 컴파일 메뉴에서 설정 가능하게 해준다.- Makefile 수정 : 경로 및 파일명(/커널소스/arch/arm/mach-pxa/Makefile) : 위와 같이 Kconfig만 수정하면 메뉴에 추가는 가능하지만 실제로 포팅을 하여 추가한 파일은 컴파일이 되지 않는다. 이를 위해 아래와 같이 한 줄을 넣어 주면 컴파일러가 새로 추가한 파일을 컴파일 한 후 커널에 추가 시킨다. : 여기까지 한 후 make menuconfig를 수행하여 나오는 화면에서 System type에서 PXA25x를 선택하면 [Hybus Xhyper255A Development Platform] 옵션이 나오는 것을 확인할 수 있다.⑤ MTD(Memory Technology Devices) 메뉴 추가 : 경로 및 파일명(/커널소스/drivers/mtd/maps/Kconfig) (/커널소스/drivers/mtd/maps/Makefile) : 전체적으로 메뉴 추가 방식은 (3)번의 아키텍처 메뉴 추가와 비교해서 특별한 것은 없고 단지 경로와 추가할 값이 달라진다. 다음의 두 파일을 수정한다.- Kconfig 수정 : 경로 및 파일명(/커널소스/drivers/mtd/maps/Kconfig) : 아래와 같이 config 항목을 하나 추가 한다. MTD_ XHYPER255는 MTD_에 위에서 설정한 보드 타입인 XHYPER255가 결합되어 이 메뉴가 XHYPER255 보드의 MTD라는 것을 나타내며 tristate 다음의 문자열은 메뉴에서 보여 질 문구가 된다. 그리고 depend on 다음의 MACH_XHYPER255 && MTD_CFI_INTELEXT && MTD_PARTITONS는 컴파일 설정에서 XHYPER255 아키텍처와 CFI(Common Flash Interface: 플래시 메모리 인터페이스)의 한 종류인 Intel/Sharp 플래시 칩과 MTD 파티션의 설정이 되어야 선택될 수 있다는 의존성을 나타낸다.- Makefile 수정 : 경로 및 파일명(/커널소스/drivers/mtd/maps/Makefile) : 아래와 같이 한 줄을 추가 한다. 위의 (3)번과 마찬가지로 메뉴에서 설정이 되면 새로 추가한 파일을 커널 컴파일에 추가시킨다는 의미이다. : 여기까지 한 후 make menuconfig를 수행하여 나오는 화면에서 Device Driver의 MTD 옵션에 가보면 [CFI Flash device mapped on Xhyper255 pxa255 eval board] 옵션이 나오는 것을 확인할 수 있다. ⑥ menuconfig 설정 : 커널소스가 있는 디렉토리에서 make menuconfig를 하여 위에서 추가한 메뉴를 선택 한 후 다른 기능들을 보드의 스펙에 맞게 선택한다. 설정을 마치게 되면 default로 /커널소스/.config 파일에 설정 정보가 저장된다. 특정 보드에 포팅을 완료 한 후에는 완료 당시의 설정 파일(.config)을 /커널소스/arch/arm/configs/에 [아키텍처타입_defconfig]의 파일명으로 설정 파일을 복사해 두는 것이 좋다.아키텍처 관련 소스 추가● Hybus xhyper255 : 경로 및 파일명 (/커널소스/arch/arm/mach-pxa/xhyper 255.c) : 파일명은 보통 보드 명으로 선택하는 것이 일반적이다. 이 파일은 메뉴에서 추가한 아키텍처 타입이 설정되면 컴파일 할 때 추가되는 파일이다. 보드에서 쓰이는 포트 번호, IRQ 타입 설정, 메모리 뱅크, CS 레지스터 설정 등을 한다. : 다음의 표는 주석을 번역한 machine_desc 구조체이다.MTD 관련 소스 추가● Hybus xhyper255 : 경로 및 파일명(/커널소스/drivers/mtd/maps/xhyper 255.c) : MTD는 아키텍처 쪽이 아닌 디바이스 드라이버 부분이다. 따라서 모듈로 커널에 포함될 수 있도록 해주어야 한다.● Hybus Xhyper255A의 헤더 파일 : 경로 및 파일명 (/커널소스/include/asm-arm/arch-pxa /xhyper255.h) : 이 파일에는 보드에서 사용하는 여러 설정 값들이 정의 되어 있다. 예를 들어 IRQ_GPIO_ADS7843, HLH 비트, LHL 비트 등등의 여러 값이 있다.H/W 스펙Processor : Intel PXA255 400MHzSDRAM : Samsung 32MFlash RAM : Intel strata flash 16MEthernet : CS8900A 10BaseTTouch screen : ADS7843USB : USB SlaveSerial : 2 PortsJTAG : 1 PortsConnector : PC104+ connectorLCD : 3.2" TFT LCD (240 * 320) InterfaceS/W 스펙CS8900 Ethernet DriverADS7843 Touch screen DriverFrame bufferUSB SlaveJFFS2 file system쪹 연재순서리눅스 커널 2.6.14 기반 PXA 270 핸들링1회 인텔 PXA270 하드웨어 스펙 및 개발환경 구축/부트로더2회 커널 내부 구조 5가지 구성 요소 분석(ARM 코어와 커널 2.6)3회 커널 엔트리 포인트 분석 및 기능 구현(시스템 콜 및 인터럽트)4회 커널 내부 구조에 기반한 커널 프로그래밍5회 모듈 프로그래밍 기반의 디바이스 드라이버 프로그래밍6회 커널 내 리얼타임 스케줄링 기법 구현7회 리얼타임 기반 하드웨어 인터럽트 및 소프트웨어 인터럽트 구현H/W 스펙Processor : Intel PXA255 400MHzSDRAM : Samsung 64M(32*2개)Flash RAM : Intel strata flash 32M(16M*2개)Ethernet : LAN91C111 10BaseTLCD : 16*2 Text LCD(2줄*20글자, Backlight)Push Button switch(input for 8 bits' signal)Serial : 1 PortGPIO(9) Input test buttonIrDA(infrared) transceiver 1 PortS/W 스펙LAN91C1111 Ethernet Driverramdisk file systemVERSION = 2PATCHLEVEL = 6SUBLEVEL = 14EXTRAVERSION = -rc5--pxa255-hybusNAME = Affluent Albatross ARCH = armCROSS_COMPILE = arm-linux-machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number xhyper255 MACH_XHYPER255 XHYPER255 888 #ifdef CONFIG_MACH_XHYPER255A mov r7, #MACH_TYPE_XHYPER255#endifconfig MACH_XHYPER255A bool "Hybus Xhyper255A Development Platform" select PXA25x select MACH_XHYPER255config MACH_XHYPER255 bool help Hybus XHyper255 Development Platformobj-$(CONFIG_MACH_XHYPER255) += xhyper255.oconfig MTD_XHYPER255 tristate "CFI Flash device mapped on Xhyper255 pxa255 eval board" depends on MACH_XHYPER255 && MTD_CFI_INTELEXT       && MTD_PARTITIONS help This provides a driver for the on-board flash of the 'xhyper255' pxa255 evaluation board.obj-$(CONFIG_MTD_XHYPER255) + = xhyper255.o#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // xhyper255 보드의 헤더 파일#include #include #include "generic.h"// hybus 보드에서 사용하는 포트 초기화unsigned short hyper_port0=0;unsigned short hyper_port1=0;unsigned short hyper_port2=0;unsigned short hyper_port3=0;// IRQ 초기화 함수static void __init xhyper255_init_irq(void){ pxa_init_irq(); // PXA 보드의 IRQ 초기화 함수를 호출 // 여기부터는 xhyper255 보드의 IRQ 초기화를 한다. set_irq_type(IRQ_GPIO_ADS7843, IRQT_FALLING); // ADS7843 touch controller return;}/* xhyper255 보드의 초기화 함수. LCD 설정 등의 초기화를 해줄 수 있다. 현재는 아무 것도 초기화 하지 않음.*/static void __init xhyper255_init(void){ return;}// 메모리 뱅크 초기화static void __initfixup_xhyper255(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi){ SET_BANK (0, 0xA0000000, 32*1024*1024); mi->nr_banks = 1;}// 이 함수는 CS 레지스터들의 입출력 가상주소, 물리주소, 길이, 도메인을 설정한다.static struct map_desc xhyper255_io_desc[] __initdata = { /* virtual physical length domain */ // CS0 : Intel Strata Flash 16M (메모리 입출력 레지스터) { 0xE8000000, 0x00000000, 0x01000000, MT_DEVICE }, // CS1 : CS89x0 (Ethernet 입출력 레지스터) { 0xF0000000, 0x04000000, 0x00100000, MT_DEVICE }, // CS1 : ADS7843/LCD (LCD 입출력 레지스터) { 0xF0200000, 0x04700000, 0x00010000, MT_DEVICE },};// 이 함수는 xhyper255의 메모리 관련 입출력 메모리 맵을 초기화해준다.static void __init xhyper255_map_io(void){ pxa_map_io(); // PXA 보드의 기본 메모리 맵 초기화 // xhyper255의 입출력 테이블 초기화 iotable_init(xhyper255_io_desc, ARRAY_SIZE(xhyper255_io_desc)); /* CS0/1의 메모리 타이밍 설정 */ MSC0 = MSC_CS(0, MSC_RBUFF(MSC_RBUFF_SLOW) | MSC_RRR(0x7) | MSC_RDN(0xf) | MSC_RDF(0xf) | MSC_RBW(1) | //16bit MSC_RT(0)) | MSC_CS(1, MSC_RBUFF(MSC_RBUFF_SLOW) | MSC_RRR(0x7) | MSC_RDN(0xf) | MSC_RDF(0xf) | MSC_RBW(1) | MSC_RT(0)); printk(KERN_INFO "MCS0 = 0x%08xn", MSC0); printk(KERN_INFO "MCS1 = 0x%08xn", MSC1); /* CS4/5의 메모리 타이밍 설정 */ MSC2 = MSC_CS(4, MSC_RBUFF(MSC_RBUFF_SLOW) | MSC_RRR(0x7) | MSC_RDN(0xf) | MSC_RDF(0xf) | MSC_RBW(1) | MSC_RT(0)) | MSC_CS(5, MSC_RBUFF(MSC_RBUFF_SLOW) | MSC_RRR(0x7) | MSC_RDN(0xf) | MSC_RDF(0xf) | MSC_RBW(1) | MSC_RT(0)); printk(KERN_INFO "MCS2 = 0x%08xn", MSC2); return;}/* 머신 설정 매크로로 커널 2.6.10 버전까지는 /커널소스/include/asm-arm/mach/ arch.h 파일에 BOOT_MEM, BOOT_PARAMS 등의 매크로를 사용했지만 커널 2.6.14는 매크로가 빠져있다. 따로 가져다 쓸 수도 있지만 machine_desc 구조체에 설정 된 멤버 그대로 사용해도 된다. 각 항목의 설명은 다음 표에 있다.*/MACHINE_START(XHYPER255, "Hybus PXA25x Development Platform") .phys_ram = 0xa0000000, .phys_io = 0x40000000, .boot_params = 0xa0000100, .io_pg_offst = io_p2v(0x40000000), .fixup = fixup_xhyper255, .map_io = xhyper255_map_io, .init_irq = xhyper255_init_irq, .timer = &pxa_timer, .init_machine = xhyper255_init,MACHINE_ENDstruct machine_desc { /* * 위에서부터 5개의 구조체 멤버는 head-armv.S 파일의 어셈블러 * 코드에서 사용된다. */ unsigned int nr; /* 아키텍처 번호 */ unsigned int phys_ram; /* 물리 시작 주소 */ unsigned int phys_io; /* 물리 입출력 시작 주소 */ unsigned int io_pg_offst; /* 입출력 페이지 테이블의 오프셋 */ const char *name; /* 아키텍처 이름 */ unsigned long boot_params; /* tagged list */ unsigned int param_offset; unsigned int video_start; /* 비디오 램의 시작 주소 */ unsigned int video_end; /* 비디오 램의 끝 주소 */ unsigned int reserve_lp0 :1; /* never has lp0 */ unsigned int reserve_lp1 :1; /* never has lp1 */ unsigned int reserve_lp2 :1; /* never has lp2 */ unsigned int soft_reboot :1; /* soft reboot */ void (*fixup)(struct machine_desc *, struct tag *, char **, struct meminfo *); /* fixup 함수 */ void (*map_io)(void); /* 입출력 매핑 함수 */ void (*init_irq)(void); struct sys_timer *timer; /* 시스템 TICK 타이머 */ void (*init_machine)(void);};#include #include #include #include #include #include #include #include #include #include #include #include #include #define BASE_ADDR 0 // 플래시 메모리의기본 시작 주소 = 0번지#define FLASH_SIZE 16*1024*1024 // 플래시 메모리 사이즈 = 16MB#define BUSWIDTH 2 // 플래시 메모리의버스 크기 = 16bitstatic void xhyper255_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len){ consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE); return;}// xhyper255의 메모리 맵의 기본 정보 설정static struct map_info xhyper255_maps[] = { { .name = "X-Hyper255 Flash", .size = FLASH_SIZE, .phys = BASE_ADDR, .bankwidth = BUSWIDTH, .inval_cache = xhyper255_map_inval_cache }};#define nmaps (sizeof(xhyper255_maps) / sizeof(xhyper255_maps[0]))/* 보드의 부트 로더의 설정 값(부트 로더의 config.h)과 같아야 한다. hybus는 플래시 메모리 설정을 부트로더, 파티션 테이블, 커널, 파일 시스템의 4 부분으로 나눈다. 따라서 config.h 파일에 기술된 주소 값에 따라서 각 부분의 크기와 시작 주소를 설정해 주어야 한다.*/static struct mtd_partition xhyper255_partitions[] = { { .name = "bootloader", .size = 0x00040000, .offset = 0x00000000, .mask_flags = MTD_WRITEABLE /* force read- only */ },{ .name = "Partition Tables", .size = 0x00080000, .offset = 0x00040000, }, { .name = "Kernel", .size = 0x00100000, .offset = 0x000C0000, }, { .name = "Filesystem", .size = FLASH_SIZE-0x001C0000, //MTDPART _SIZ_FULL, .offset = 0x001C0000, }};// MTD 파티션 생성을 위한 변수static struct mtd_info *mymtds[nmaps];static struct mtd_partition *parsed_parts[nmaps];static int nr_parsed_parts[nmaps];// xhyper255의 메모리 초기화 함수이다. MTD 파티션 등을 생성한다.static int __init init_xhyper255(void){ int res=0, i; const char *probes[] = { 0 }; // { "RedBoot", "cmdlinepart", 0 }; for (i = 0; i < nmaps; i++) { xhyper255_maps[i].virt = ioremap(xhyper255_maps[i].phys, xhyper255_maps[i].size); if (!xhyper255_maps[i].virt) { printk(KERN_WARNING "Failed to ioremap %sn", xhyper255_maps[i].name); if (!res) res = -ENOMEM; continue; } xhyper255_maps[i].cached = __ioremap(xhyper255_maps[i].phys, xhyper255_maps[i].size, L_PTE_CACHEABLE, 1); if (!xhyper255_maps[i].cached) printk(KERN_WARNING "Failed to ioremap cached %sn", xhyper255_maps[i].name); simple_map_init(&xhyper255_maps[i]); printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)n", xhyper255_maps[i].name, xhyper255_maps[i].phys, xhyper255_maps[i].bankwidth * 8); mymtds[i] = do_map_probe("cfi_probe", &xhyper255 _maps[i]); if (!mymtds[i]) { iounmap((void *)xhyper255_maps[i].virt); if (xhyper255_maps[i].cached) iounmap(xhyper255 _maps[i].cached); if (!res) res = -EIO; continue; } mymtds[i]->owner = THIS_MODULE; res = parse_mtd_partitions(mymtds[i], probes, &parsed_parts[i], 0); if (res > 0) nr_parsed_parts[i] = res; } for (i=0; i < nmaps; i++) if (!mymtds[i]) return res; for (i=0; i < nmaps; i++) { if (!mymtds[i]) { printk(KERN_WARNING "%s is absent. Skippingn", xhyper255_maps[i].name); } else if (nr_parsed_parts[i]) { add_mtd_partitions(mymtds[i], parsed_parts[i], nr_ parsed_parts[i]); } else if (!i) { printk("Using static partitions on %sn", xhyper255 _maps[i].name); add_mtd_partitions(mymtds[i], xhyper255_ partitions, ARRAY_SIZE(xhyper255_partitions)); } else { printk("Registering %s as whole devicen", xhyper255_maps[i].name); add_mtd_device(mymtds[i]); } } return 0; }// 드라이버 해제 시 MTD 파티션 등을 메모리에서 뺀다. static void __exit cleanup_xhyper255(void){ int i; for (i=0; i < nmaps; i++){ if (!mymtds[i]) continue; if (nr_parsed_parts[i] || !i) del_mtd_partitions(mymtds[i]); else del_mtd_device(mymtds[i]); map_destroy(mymtds[i]); iounmap((void *)xhyper255_maps[i].virt); if (xhyper255_maps[i].cached) iounmap(xhyper255_maps[i].cached); if (parsed_parts[i]) kfree(parsed_parts[i]); } }// 모듈 초기화와 해제 함수를 지정해주어야 한다.module_init(init_xhyper255);module_exit(cleanup_xhyper255);// 모듈 라이센스, 작성자, 설명 등의 정보를 써준다.MODULE_LICENSE("GPL");MODULE_AUTHOR("Hur Wonkang ");MODULE_DESCRIPTION("MTD map driver for Hybus XHyper255A");#ifndef __ASM_MACH_XHYPER255_H#define __ASM_MACH_XHYPER255_H#endif#define MSC_CS(cs,val) ((val)<<((cs&1)<<4))#define MSC_RBUFF_SHIFT 15#define MSC_RBUFF_SLOW (0)#define MSC_RBUFF_FAST (1)#define MSC_RBUFF(x) ((x)<
회원가입 후 이용바랍니다.
개의 댓글
0 / 400
댓글 정렬
BEST댓글
BEST 댓글 답글과 추천수를 합산하여 자동으로 노출됩니다.
댓글삭제
삭제한 댓글은 다시 복구할 수 없습니다.
그래도 삭제하시겠습니까?
댓글수정
댓글 수정은 작성 후 1분내에만 가능합니다.
/ 400
내 댓글 모음
저작권자 © 테크월드뉴스 무단전재 및 재배포 금지