From owner-freebsd-hackers Tue Mar 11 06:27:38 1997 Return-Path: Received: (from root@localhost) by freefall.freebsd.org (8.8.5/8.8.5) id GAA06035 for hackers-outgoing; Tue, 11 Mar 1997 06:27:38 -0800 (PST) Received: from chouette.inria.fr (chouette.inria.fr [138.96.24.103]) by freefall.freebsd.org (8.8.5/8.8.5) with ESMTP id GAA06030 for ; Tue, 11 Mar 1997 06:27:36 -0800 (PST) Received: by chouette.inria.fr (8.8.5/8.6.12) id PAA05582; Tue, 11 Mar 1997 15:27:30 +0100 (MET) Date: Tue, 11 Mar 1997 15:27:30 +0100 (MET) Message-Id: <199703111427.PAA05582@chouette.inria.fr> From: Emmanuel Duros To: freebsd-hackers@freebsd.org Subject: Pb using DMA - Physical addressing Reply-to: Emmanuel.Duros@sophia.inria.fr Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk Hi, I am currently writing a device driver (isa bus) for a communication card (satellite reception/emission cards) that uses DMA transfers. I have got a peace of code that works fine under DOS but as I insert it into the freebsd device driver code nothing happens. I think the problem comes from the mapping of virtual addresses into physical addresses (?). Unfortunately I have not found much documentation on this... Here is the simple C code for dos: ------- DOS /* * transfers a 188 byte buffer from * memory to the device using drq 6 */ u_char buf[188]; u_long addr; u_char lsb, msb, page, lcnt, hcnt; dma_ch = 6; addr = ((unsigned long)FP_SEG ( buf ) << 4) /* get physical address */ + FP_OFF ( buf ); lsb = (u_char)(addr >> 1); msb = (u_char)(addr >> 9); page = (u_char)(addr >> 16); sz_dma = 188/2 - 1; lcnt = sz_bma; hcnt = sz_dma >> 8; _disable(); outp (SNGL_MASK_reg( dma_ch ) , DISABLE( dma_ch )); /* DMA_MODE = BLOCK|ADDR_INC|AUTO_DISABLE|READ|(dma_ch-4) */ outp (MODE_reg( dma_ch ) , DMA_MODE); outp (CLR_BYTE_PTR_reg( dma_ch ) , 0); outp (BASE_ADDR_reg( dma_ch ) , lsb); outp (BASE_ADDR_reg( dma_ch ) , msb); outp (PAGE_ADDR_reg( dma_ch ) , page); outp (CLR_BYTE_PTR_reg( dma_ch ) , 0); outp (COUNT_reg( dma_ch ) , lcnt); outp (COUNT_reg(dma_ch ) , hcnt); _enable(); outp (SNGL_MASK_reg( dma_ch ), ENABLE( dma_ch )); outp (SNGL_MASK_reg( dma_ch ), DISABLE( dma_ch )); -------- Now is the very similare peace of code I wrote for the FreeBSD driver: -------- FreeBSD /* * transfers a 188 byte buffer from * memory to the device using drq 6 */ buf = malloc( 188, M_DEVBUF, M_NOWAIT); /* this is from the attach function */ /* am I sure that buf < 16M ??? */ /* filling buffer here */ addr = pmap_extract(pmap_kernel(), (vm_offset_t) buf); /* I found this function, but not quite sure of its behavior) /* or addr = (u_int) buf; ??? */ lsb = (u_char)(addr >> 1); msb = (u_char)(addr >> 9); page = (u_char)(addr >> 16 & 0xFE); sz_dma = 188/2 - 1; lcnt = sz_dma; hcnt = sz_dma >> 8; outb (SNGL_MASK_reg( dma_ch ) , DISABLE( dma_ch )); outb (MODE_reg( dma_ch ) , DMA_MODE); outb (CLR_BYTE_PTR_reg( dma_ch ), 0); outb (BASE_ADDR_reg( dma_ch ) , lsb); outb (BASE_ADDR_reg( dma_ch ) , msb); outb (PAGE_ADDR_reg( dma_ch ) , page); outb (CLR_BYTE_PTR_reg( dma_ch ), 0); outb (COUNT_reg( dma_ch ) , lcnt); outb (COUNT_reg( dma_ch ) , hcnt); outb (SNGL_MASK_reg( dma_ch ), ENABLE( dma_ch )); outb (SNGL_MASK_reg( dma_ch ), DISABLE( dma_ch )); -------- I think I do not give the DMA the correct address of buf, how can this be done ? If someone had any ideas on the problem, I would be very glad to hear them ! Could anybody explain the relation between physical addressing and virtual addressing ? One last question, is it possible to develop in the user space applications that would handle dma transfers ? In fact, I am a bit fed up with rebooting my PC every time I recompile the kernel ! Thanks for your help... Emmanuel +--------------------------------------------------------------------+ |Emmanuel Duros | Emmanuel.Duros@sophia.inria.fr| |INRIA Sophia Antipolis | Projet RODEO | |2004, Route des Lucioles BP 93 | Phone : +33 04 93 65 79 42 | |06902 Sophia Antipolis CEDEX France | Fax : +33 04 93 65 77 65 | +--------------------------------------------------------------------+