📄 safl.c
字号:
// #========================================================================// #// # safl.c// #// # Linux driver for Intel(R) StrongARM(R) PCI-based coprocessor boards.// #// #========================================================================// ####COPYRIGHTBEGIN####// // ------------------------------------------- // The contents of this file are subject to the Red Hat eCos Public License // Version 1.1 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.redhat.com/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations under // the License. // // The Original Code is eCos - Embedded Configurable Operating System, // released September 30, 1998. // // The Initial Developer of the Original Code is Red Hat. // Portions created by Red Hat are // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. // All Rights Reserved. // ------------------------------------------- // // ####COPYRIGHTEND####// #========================================================================// ######DESCRIPTIONBEGIN####// #// # Author(s): msalter// # Contributors: msalter// # Date: 1999-04-02// # Purpose: Linux driver for Intel(R) StrongARM(R) PCI-based// # coprocessor boards// # Description: This module currently supports EBSA-285 and SA-IOP.// # Intel is a Registered Trademark of Intel Corporation.// # StrongARM is a Registered Trademark of Advanced RISC// # Machines Limited.// # Other Brands and Trademarks are the property of their// # respective owners.// #// #####DESCRIPTIONEND####// #// #========================================================================static char *version ="safl.c:v0.01H 04/02/99 Mark Salter, Red Hat.\n";#include <linux/module.h>#include <linux/config.h>#include <linux/version.h>#ifdef MODVERSIONS#include <linux/modversions.h>#endif#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/miscdevice.h>#include <linux/malloc.h>#include <linux/mm.h>#include <linux/pci.h>#include <linux/signal.h>#include <linux/ioport.h>#include <linux/fcntl.h>#include <asm/pgtable.h>#include <asm/page.h>#include <linux/sched.h>#include <asm/segment.h>#ifdef CONFIG_PROC_FS#include <linux/proc_fs.h>#endif#include <asm/io.h>#include <asm/system.h>#if LINUX_VERSION_CODE >= 0x020100#include <linux/init.h>#include <linux/vmalloc.h>#else#include <linux/bios32.h>#define __initfunc(x) x#endif#if LINUX_VERSION_CODE < 0x20155#define PCI_SUPPORT_VER1#else#define PCI_SUPPORT_VER2#endif#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115MODULE_AUTHOR("Mark Salter <msalter@redhat.com>");MODULE_DESCRIPTION("Intel(R) StrongARM(R) FLASH driver for PCI EVBs");#endif/* This isn't in /usr/include/linux/pci.h */#ifndef PCI_DEVICE_ID_DEC_IOP#define PCI_DEVICE_ID_DEC_21554 0x46#endif#ifndef PCI_DEVICE_ID_DEC_21285#define PCI_DEVICE_ID_DEC_21285 0x1065#endif/* somewhat arbitrary minor number. Major number is 10 (misc). */#define SAFL_MINOR 178#define FLASH_SZ (4 * 1024 * 1024)static int safl_open( struct inode *inode, struct file *file );static int safl_close( struct inode *inode, struct file *file );#if LINUX_VERSION_CODE >= 0x020100static int safl_mmap(struct file * file, struct vm_area_struct * vma);#elsestatic int safl_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);#endifstatic int safl_debug = 0;static unsigned long csr_ioaddr;static unsigned long flash_addr;static struct file_operations safl_fops = { NULL, /* lseek */ NULL, /* read */ NULL, /* write */ NULL, /* readdir */ NULL, /* poll */ NULL, /* ioctl */ safl_mmap, /* mmap */ safl_open, /* open */ NULL, /* flush */ safl_close /* close */};static struct miscdevice safl_dev = { SAFL_MINOR, "SA-FLASH", &safl_fops};/* PCI configuration space information. */static u8 safl_pci_bus, safl_pci_devfn;static int safl_devid;#ifdef PCI_SUPPORT_VER2static struct pci_dev *safl_pdev;#endifstatic int safl_open_cnt = 0; /* #times opened */__initfunc(int safl_scan(void)){ if (pcibios_present()) { int index; /* * Search for an EBSA-285 board or an IOP board. Stop at * first one found. */ for (index = 0; index < 8; index++) { if (pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21554, index, &safl_pci_bus, &safl_pci_devfn) == PCIBIOS_SUCCESSFUL) { safl_devid = PCI_DEVICE_ID_DEC_21554; break; } if (pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, index, &safl_pci_bus, &safl_pci_devfn) == PCIBIOS_SUCCESSFUL) { safl_devid = PCI_DEVICE_ID_DEC_21285; break; } } if (index < 8) {#ifdef PCI_SUPPORT_VER2 safl_pdev = pci_find_slot(safl_pci_bus, safl_pci_devfn);#endif misc_register(&safl_dev); return 0; } } if (safl_debug) printk(KERN_INFO "Can't find device.\n"); return -ENODEV;}intinit_module(void){ if (safl_debug) printk(KERN_INFO "%s", version); return safl_scan();}/* * Dword read from configuration space of secondary PCI bus. */static unsigned intsconfig_read(int addr){ unsigned int val; outw(2, csr_ioaddr + 0x12); /* enable downstream config */ outl(addr | (1<<24), csr_ioaddr + 0x00); val = inl(csr_ioaddr + 4); outw(0, csr_ioaddr + 0x12); /* disable downstream config */ return val;}/* * Dword write to configuration space of secondary PCI bus. */static voidsconfig_write(int addr, int val){ outw(2, csr_ioaddr + 0x12); /* enable downstream config */ outl(addr | (1<<24), csr_ioaddr + 0x00); outl(val, csr_ioaddr + 4); outw(0, csr_ioaddr + 0x12); /* disable downstream config */}/* * Dword read from configuration space of primary PCI bus. */static unsigned intpconfig_read(int addr){ unsigned int val;#ifdef PCI_SUPPORT_VER2 pci_read_config_dword(safl_pdev, addr, &val);#else pcibios_read_config_dword(safl_pci_bus, safl_pci_devfn, addr, &val);#endif return val;}/* * Dword write to configuration space of primary PCI bus. */static voidpconfig_write(int addr, int val){#ifdef PCI_SUPPORT_VER2 pci_write_config_dword(safl_pdev, addr, val);#else pcibios_write_config_dword(safl_pci_bus, safl_pci_devfn, addr, val);#endif}static intsafl_open( struct inode *inode, struct file *file ){ if (safl_open_cnt) { if (safl_debug) printk(KERN_INFO "SA-Flash already open.\n"); return( -EBUSY ); } if (safl_devid == PCI_DEVICE_ID_DEC_21554) { csr_ioaddr = pconfig_read(PCI_BASE_ADDRESS_1) & PCI_BASE_ADDRESS_IO_MASK; flash_addr = pconfig_read(PCI_BASE_ADDRESS_3) & PCI_BASE_ADDRESS_MEM_MASK; if (safl_debug) { printk(KERN_INFO "IOP: csr_io[%lx].\n", csr_ioaddr); printk(KERN_INFO "IOP: flash_add[%lx].\n", flash_addr); } /* * Need to configure downstream side of 21554. * These addresses are pretty arbitrary. */ pconfig_write(0x50, 0xf0000000); /* secondary CSR memory */ pconfig_write(0x54, 0xf201); /* secondary CSR I/O */ pconfig_write(0x58, 0xf401); /* Upstream I/O */ pconfig_write(0x5c, 0xf1000008); /* Upstream memory 1 */ pconfig_write(0x44, 0x29000017); /* enable mem an I/O */ /* set downstream mem2 xlate base */ pconfig_write(0x9c, 0xA0000000); /* set 21285 ROM address to same */ sconfig_write(0x30, 0xA0000001); /* set 21285 ROM write byte address */ sconfig_write(0x68, 0); } else if (safl_devid == PCI_DEVICE_ID_DEC_21285) { /* * I'm not sure how best to handle this. Basically, you want * to assign a physical address for the expansion ROM space * of the 21285. There doesn't appear to be a good way to * find an unused physical space for the PCI bus. This seems * to work for the limited number of motherboards that this * code has been tested on. YMMV. */ flash_addr = 0xb0000000; pconfig_write(PCI_ROM_ADDRESS, flash_addr | PCI_ROM_ADDRESS_ENABLE); } safl_open_cnt++; MOD_INC_USE_COUNT; return 0;}static intsafl_close( struct inode *inode, struct file *file ){ safl_open_cnt--; if (safl_devid == PCI_DEVICE_ID_DEC_21285) pconfig_write(PCI_ROM_ADDRESS, 0); if (safl_devid == PCI_DEVICE_ID_DEC_21554) sconfig_write(0x30, 0); MOD_DEC_USE_COUNT; return 0;}static inline unsigned longpgprot_noncached(unsigned long prot){#if LINUX_VERSION_CODE >= 0x020100 if (boot_cpu_data.x86 > 3) prot |= _PAGE_PCD;#endif return prot;}static int#if LINUX_VERSION_CODE >= 0x020100safl_mmap(struct file * file, struct vm_area_struct * vma)#elsesafl_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)#endif{ unsigned long size; if (vma->vm_offset != 0) return -EINVAL; size = vma->vm_end - vma->vm_start; if (size > FLASH_SZ) return -EINVAL; pgprot_val(vma->vm_page_prot) = pgprot_noncached(pgprot_val(vma->vm_page_prot));#if LINUX_VERSION_CODE >= 0x020100 vma->vm_flags |= VM_IO;#endif if (remap_page_range(vma->vm_start, flash_addr, size, vma->vm_page_prot)) return -EAGAIN;#if LINUX_VERSION_CODE < 0x020100 vma->vm_inode = inode; inode->i_count++;#endif return 0;}voidcleanup_module(void){ misc_deregister(&safl_dev);}/* * Local variables: * compile-command: "cc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c safl.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -