18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Architecture specific parts of the Floppy driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 58c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 68c2ecf20Sopenharmony_ci * for more details. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 1995 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#ifndef _ASM_X86_FLOPPY_H 118c2ecf20Sopenharmony_ci#define _ASM_X86_FLOPPY_H 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * The DMA channel used by the floppy controller cannot access data at 178c2ecf20Sopenharmony_ci * addresses >= 16MB 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Went back to the 1MB limit, as some people had problems with the floppy 208c2ecf20Sopenharmony_ci * driver otherwise. It doesn't matter much for performance anyway, as most 218c2ecf20Sopenharmony_ci * floppy accesses go through the track buffer. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci#define _CROSS_64KB(a, s, vdma) \ 248c2ecf20Sopenharmony_ci (!(vdma) && \ 258c2ecf20Sopenharmony_ci ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64)) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define CROSS_64KB(a, s) _CROSS_64KB(a, s, use_virtual_dma & 1) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define SW fd_routine[use_virtual_dma & 1] 318c2ecf20Sopenharmony_ci#define CSW fd_routine[can_use_virtual_dma & 1] 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define fd_inb(base, reg) inb_p((base) + (reg)) 358c2ecf20Sopenharmony_ci#define fd_outb(value, base, reg) outb_p(value, (base) + (reg)) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define fd_request_dma() CSW._request_dma(FLOPPY_DMA, "floppy") 388c2ecf20Sopenharmony_ci#define fd_free_dma() CSW._free_dma(FLOPPY_DMA) 398c2ecf20Sopenharmony_ci#define fd_enable_irq() enable_irq(FLOPPY_IRQ) 408c2ecf20Sopenharmony_ci#define fd_disable_irq() disable_irq(FLOPPY_IRQ) 418c2ecf20Sopenharmony_ci#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) 428c2ecf20Sopenharmony_ci#define fd_get_dma_residue() SW._get_dma_residue(FLOPPY_DMA) 438c2ecf20Sopenharmony_ci#define fd_dma_mem_alloc(size) SW._dma_mem_alloc(size) 448c2ecf20Sopenharmony_ci#define fd_dma_setup(addr, size, mode, io) SW._dma_setup(addr, size, mode, io) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define FLOPPY_CAN_FALLBACK_ON_NODMA 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int virtual_dma_count; 498c2ecf20Sopenharmony_cistatic int virtual_dma_residue; 508c2ecf20Sopenharmony_cistatic char *virtual_dma_addr; 518c2ecf20Sopenharmony_cistatic int virtual_dma_mode; 528c2ecf20Sopenharmony_cistatic int doing_pdma; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic irqreturn_t floppy_hardint(int irq, void *dev_id) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci unsigned char st; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#undef TRACE_FLPY_INT 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 618c2ecf20Sopenharmony_ci static int calls; 628c2ecf20Sopenharmony_ci static int bytes; 638c2ecf20Sopenharmony_ci static int dma_wait; 648c2ecf20Sopenharmony_ci#endif 658c2ecf20Sopenharmony_ci if (!doing_pdma) 668c2ecf20Sopenharmony_ci return floppy_interrupt(irq, dev_id); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 698c2ecf20Sopenharmony_ci if (!calls) 708c2ecf20Sopenharmony_ci bytes = virtual_dma_count; 718c2ecf20Sopenharmony_ci#endif 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci { 748c2ecf20Sopenharmony_ci int lcount; 758c2ecf20Sopenharmony_ci char *lptr; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci st = 1; 788c2ecf20Sopenharmony_ci for (lcount = virtual_dma_count, lptr = virtual_dma_addr; 798c2ecf20Sopenharmony_ci lcount; lcount--, lptr++) { 808c2ecf20Sopenharmony_ci st = inb(virtual_dma_port + FD_STATUS); 818c2ecf20Sopenharmony_ci st &= STATUS_DMA | STATUS_READY; 828c2ecf20Sopenharmony_ci if (st != (STATUS_DMA | STATUS_READY)) 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci if (virtual_dma_mode) 858c2ecf20Sopenharmony_ci outb_p(*lptr, virtual_dma_port + FD_DATA); 868c2ecf20Sopenharmony_ci else 878c2ecf20Sopenharmony_ci *lptr = inb_p(virtual_dma_port + FD_DATA); 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci virtual_dma_count = lcount; 908c2ecf20Sopenharmony_ci virtual_dma_addr = lptr; 918c2ecf20Sopenharmony_ci st = inb(virtual_dma_port + FD_STATUS); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 958c2ecf20Sopenharmony_ci calls++; 968c2ecf20Sopenharmony_ci#endif 978c2ecf20Sopenharmony_ci if (st == STATUS_DMA) 988c2ecf20Sopenharmony_ci return IRQ_HANDLED; 998c2ecf20Sopenharmony_ci if (!(st & STATUS_DMA)) { 1008c2ecf20Sopenharmony_ci virtual_dma_residue += virtual_dma_count; 1018c2ecf20Sopenharmony_ci virtual_dma_count = 0; 1028c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 1038c2ecf20Sopenharmony_ci printk(KERN_DEBUG "count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", 1048c2ecf20Sopenharmony_ci virtual_dma_count, virtual_dma_residue, calls, bytes, 1058c2ecf20Sopenharmony_ci dma_wait); 1068c2ecf20Sopenharmony_ci calls = 0; 1078c2ecf20Sopenharmony_ci dma_wait = 0; 1088c2ecf20Sopenharmony_ci#endif 1098c2ecf20Sopenharmony_ci doing_pdma = 0; 1108c2ecf20Sopenharmony_ci floppy_interrupt(irq, dev_id); 1118c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 1148c2ecf20Sopenharmony_ci if (!virtual_dma_count) 1158c2ecf20Sopenharmony_ci dma_wait++; 1168c2ecf20Sopenharmony_ci#endif 1178c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void fd_disable_dma(void) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci if (!(can_use_virtual_dma & 1)) 1238c2ecf20Sopenharmony_ci disable_dma(FLOPPY_DMA); 1248c2ecf20Sopenharmony_ci doing_pdma = 0; 1258c2ecf20Sopenharmony_ci virtual_dma_residue += virtual_dma_count; 1268c2ecf20Sopenharmony_ci virtual_dma_count = 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int vdma_request_dma(unsigned int dmanr, const char *device_id) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void vdma_nop(unsigned int dummy) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int vdma_get_dma_residue(unsigned int dummy) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci return virtual_dma_count + virtual_dma_residue; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int fd_request_irq(void) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci if (can_use_virtual_dma) 1488c2ecf20Sopenharmony_ci return request_irq(FLOPPY_IRQ, floppy_hardint, 1498c2ecf20Sopenharmony_ci 0, "floppy", NULL); 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci return request_irq(FLOPPY_IRQ, floppy_interrupt, 1528c2ecf20Sopenharmony_ci 0, "floppy", NULL); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic unsigned long dma_mem_alloc(unsigned long size) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return __get_dma_pages(GFP_KERNEL|__GFP_NORETRY, get_order(size)); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic unsigned long vdma_mem_alloc(unsigned long size) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci return (unsigned long)vmalloc(size); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci#define nodma_mem_alloc(size) vdma_mem_alloc(size) 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void _fd_dma_mem_free(unsigned long addr, unsigned long size) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci if ((unsigned long)addr >= (unsigned long)high_memory) 1728c2ecf20Sopenharmony_ci vfree((void *)addr); 1738c2ecf20Sopenharmony_ci else 1748c2ecf20Sopenharmony_ci free_pages(addr, get_order(size)); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#define fd_dma_mem_free(addr, size) _fd_dma_mem_free(addr, size) 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic void _fd_chose_dma_mode(char *addr, unsigned long size) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci if (can_use_virtual_dma == 2) { 1828c2ecf20Sopenharmony_ci if ((unsigned long)addr >= (unsigned long)high_memory || 1838c2ecf20Sopenharmony_ci isa_virt_to_bus(addr) >= 0x1000000 || 1848c2ecf20Sopenharmony_ci _CROSS_64KB(addr, size, 0)) 1858c2ecf20Sopenharmony_ci use_virtual_dma = 1; 1868c2ecf20Sopenharmony_ci else 1878c2ecf20Sopenharmony_ci use_virtual_dma = 0; 1888c2ecf20Sopenharmony_ci } else { 1898c2ecf20Sopenharmony_ci use_virtual_dma = can_use_virtual_dma & 1; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci#define fd_chose_dma_mode(addr, size) _fd_chose_dma_mode(addr, size) 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int vdma_dma_setup(char *addr, unsigned long size, int mode, int io) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci doing_pdma = 1; 1998c2ecf20Sopenharmony_ci virtual_dma_port = io; 2008c2ecf20Sopenharmony_ci virtual_dma_mode = (mode == DMA_MODE_WRITE); 2018c2ecf20Sopenharmony_ci virtual_dma_addr = addr; 2028c2ecf20Sopenharmony_ci virtual_dma_count = size; 2038c2ecf20Sopenharmony_ci virtual_dma_residue = 0; 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int hard_dma_setup(char *addr, unsigned long size, int mode, int io) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci#ifdef FLOPPY_SANITY_CHECK 2108c2ecf20Sopenharmony_ci if (CROSS_64KB(addr, size)) { 2118c2ecf20Sopenharmony_ci printk("DMA crossing 64-K boundary %p-%p\n", addr, addr+size); 2128c2ecf20Sopenharmony_ci return -1; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci#endif 2158c2ecf20Sopenharmony_ci /* actual, physical DMA */ 2168c2ecf20Sopenharmony_ci doing_pdma = 0; 2178c2ecf20Sopenharmony_ci clear_dma_ff(FLOPPY_DMA); 2188c2ecf20Sopenharmony_ci set_dma_mode(FLOPPY_DMA, mode); 2198c2ecf20Sopenharmony_ci set_dma_addr(FLOPPY_DMA, isa_virt_to_bus(addr)); 2208c2ecf20Sopenharmony_ci set_dma_count(FLOPPY_DMA, size); 2218c2ecf20Sopenharmony_ci enable_dma(FLOPPY_DMA); 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic struct fd_routine_l { 2268c2ecf20Sopenharmony_ci int (*_request_dma)(unsigned int dmanr, const char *device_id); 2278c2ecf20Sopenharmony_ci void (*_free_dma)(unsigned int dmanr); 2288c2ecf20Sopenharmony_ci int (*_get_dma_residue)(unsigned int dummy); 2298c2ecf20Sopenharmony_ci unsigned long (*_dma_mem_alloc)(unsigned long size); 2308c2ecf20Sopenharmony_ci int (*_dma_setup)(char *addr, unsigned long size, int mode, int io); 2318c2ecf20Sopenharmony_ci} fd_routine[] = { 2328c2ecf20Sopenharmony_ci { 2338c2ecf20Sopenharmony_ci ._request_dma = request_dma, 2348c2ecf20Sopenharmony_ci ._free_dma = free_dma, 2358c2ecf20Sopenharmony_ci ._get_dma_residue = get_dma_residue, 2368c2ecf20Sopenharmony_ci ._dma_mem_alloc = dma_mem_alloc, 2378c2ecf20Sopenharmony_ci ._dma_setup = hard_dma_setup 2388c2ecf20Sopenharmony_ci }, 2398c2ecf20Sopenharmony_ci { 2408c2ecf20Sopenharmony_ci ._request_dma = vdma_request_dma, 2418c2ecf20Sopenharmony_ci ._free_dma = vdma_nop, 2428c2ecf20Sopenharmony_ci ._get_dma_residue = vdma_get_dma_residue, 2438c2ecf20Sopenharmony_ci ._dma_mem_alloc = vdma_mem_alloc, 2448c2ecf20Sopenharmony_ci ._dma_setup = vdma_dma_setup 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci}; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int FDC1 = 0x3f0; 2508c2ecf20Sopenharmony_cistatic int FDC2 = -1; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* 2538c2ecf20Sopenharmony_ci * Floppy types are stored in the rtc's CMOS RAM and so rtc_lock 2548c2ecf20Sopenharmony_ci * is needed to prevent corrupted CMOS RAM in case "insmod floppy" 2558c2ecf20Sopenharmony_ci * coincides with another rtc CMOS user. Paul G. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci#define FLOPPY0_TYPE \ 2588c2ecf20Sopenharmony_ci({ \ 2598c2ecf20Sopenharmony_ci unsigned long flags; \ 2608c2ecf20Sopenharmony_ci unsigned char val; \ 2618c2ecf20Sopenharmony_ci spin_lock_irqsave(&rtc_lock, flags); \ 2628c2ecf20Sopenharmony_ci val = (CMOS_READ(0x10) >> 4) & 15; \ 2638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rtc_lock, flags); \ 2648c2ecf20Sopenharmony_ci val; \ 2658c2ecf20Sopenharmony_ci}) 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci#define FLOPPY1_TYPE \ 2688c2ecf20Sopenharmony_ci({ \ 2698c2ecf20Sopenharmony_ci unsigned long flags; \ 2708c2ecf20Sopenharmony_ci unsigned char val; \ 2718c2ecf20Sopenharmony_ci spin_lock_irqsave(&rtc_lock, flags); \ 2728c2ecf20Sopenharmony_ci val = CMOS_READ(0x10) & 15; \ 2738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rtc_lock, flags); \ 2748c2ecf20Sopenharmony_ci val; \ 2758c2ecf20Sopenharmony_ci}) 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci#define N_FDC 2 2788c2ecf20Sopenharmony_ci#define N_DRIVE 8 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci#define EXTRA_FLOPPY_PARAMS 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci#endif /* _ASM_X86_FLOPPY_H */ 283