hm2_pci.c

来自「CNC 的开放码,EMC2 V2.2.8版」· C语言 代码 · 共 577 行 · 第 1/2 页

C
577
字号
////    Copyright (C) 2007-2008 Sebastian Kuzminsky////    This program is free software; you can redistribute it and/or modify//    it under the terms of the GNU General Public License as published by//    the Free Software Foundation; either version 2 of the License, or//    (at your option) any later version.////    This program is distributed in the hope that it will be useful,//    but WITHOUT ANY WARRANTY; without even the implied warranty of//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the//    GNU General Public License for more details.////    You should have received a copy of the GNU General Public License//    along with this program; if not, write to the Free Software//    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA//#include <linux/pci.h>#include "rtapi.h"#include "rtapi_app.h"#include "rtapi_string.h"#include "hal.h"#include "hostmot2-lowlevel.h"#include "hm2_pci.h"MODULE_LICENSE("GPL");MODULE_AUTHOR("Sebastian Kuzminsky");MODULE_DESCRIPTION("Driver for HostMot2 on the 5i20, 4i65, and 5i22 Anything I/O boards from Mesa Electronics");MODULE_SUPPORTED_DEVICE("Mesa-AnythingIO-5i20");  // FIXMEstatic char *config[HM2_PCI_MAX_BOARDS];static int num_config_strings = HM2_PCI_MAX_BOARDS;module_param_array(config, charp, &num_config_strings, S_IRUGO);MODULE_PARM_DESC(config, "config string for the AnyIO boards (see hostmot2(9) manpage)");static int comp_id;// FIXME: should probably have a linked list of boards instead of an arraystatic hm2_pci_t hm2_pci_board[HM2_PCI_MAX_BOARDS];static int num_boards = 0;static int num_5i20 = 0;static int num_5i22 = 0;static int num_5i23 = 0;static int num_4i65 = 0;static int num_4i68 = 0;static struct pci_device_id hm2_pci_tbl[] = {    // 5i20    {        .vendor = 0x10b5,        .device = HM2_PCI_DEV_PLX9030,        .subvendor = 0x10b5,        .subdevice = HM2_PCI_SSDEV_5I20,    },    // 4i65    {        .vendor = 0x10b5,        .device = HM2_PCI_DEV_PLX9030,        .subvendor = 0x10b5,        .subdevice = HM2_PCI_SSDEV_4I65,    },    // 5i22-1.0M    {        .vendor = 0x10b5,        .device = HM2_PCI_DEV_PLX9054,        .subvendor = 0x10b5,        .subdevice = HM2_PCI_SSDEV_5I22_10,    },    // 5i22-1.5M    {        .vendor = 0x10b5,        .device = HM2_PCI_DEV_PLX9054,        .subvendor = 0x10b5,        .subdevice = HM2_PCI_SSDEV_5I22_15,    },    // 5i23    {        .vendor = 0x10b5,        .device = HM2_PCI_DEV_PLX9054,        .subvendor = 0x10b5,        .subdevice = HM2_PCI_SSDEV_5I23,    },    // 4i68 (old SSID)    {        .vendor = 0x10b5,        .device = HM2_PCI_DEV_PLX9054,        .subvendor = 0x10b5,        .subdevice = HM2_PCI_SSDEV_4I68_OLD,    },    // 4i68 (new SSID)    {        .vendor = 0x10b5,        .device = HM2_PCI_DEV_PLX9054,        .subvendor = 0x10b5,        .subdevice = HM2_PCI_SSDEV_4I68,    },    {0,},};MODULE_DEVICE_TABLE(pci, hm2_pci_tbl);// // these are the "low-level I/O" functions exported up//static int hm2_pci_read(hm2_lowlevel_io_t *this, u32 addr, void *buffer, int size) {    hm2_pci_t *board = this->private;    memcpy(buffer, (board->base + addr), size);    return 1;  // success}static int hm2_pci_write(hm2_lowlevel_io_t *this, u32 addr, void *buffer, int size) {    hm2_pci_t *board = this->private;    memcpy((board->base + addr), buffer, size);    return 1;  // success}static int hm2_plx9030_program_fpga(hm2_lowlevel_io_t *this, const bitfile_t *bitfile) {    hm2_pci_t *board = this->private;    int i;    u32 status, control;    // set /WRITE low for data transfer, and turn on LED    status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET);    control = status & ~_WRITE_MASK & ~_LED_MASK;    outl(control, board->ctrl_base_addr + CTRL_STAT_OFFSET);    // program the FPGA    for (i = 0; i < bitfile->e.size; i ++) {        outb(bitfile->e.data[i], board->data_base_addr);    }    // all bytes transferred, make sure FPGA is all set up now    status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET);    if (!(status & _INIT_MASK)) {	// /INIT goes low on CRC error	THIS_ERR("FPGA asserted /INIT: CRC error\n");        goto fail;    }    if (!(status & DONE_MASK)) {	THIS_ERR("FPGA did not assert DONE\n");	goto fail;    }    // turn off write enable and LED    control = status | _WRITE_MASK | _LED_MASK;    outl(control, board->ctrl_base_addr + CTRL_STAT_OFFSET);    return 0;fail:    // set /PROGRAM low (reset device), /WRITE high and LED off    status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET);    control = status & ~_PROGRAM_MASK;    control |= _WRITE_MASK | _LED_MASK;    outl(control, board->ctrl_base_addr + CTRL_STAT_OFFSET);    return -EIO;}static int hm2_plx9030_reset(hm2_lowlevel_io_t *this) {    hm2_pci_t *board = this->private;    u32 status;    u32 control;    status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET);    // set /PROGRAM bit low to reset the FPGA    control = status & ~_PROGRAM_MASK;    // set /WRITE and /LED high (idle state)    control |= _WRITE_MASK | _LED_MASK;    // and write it back    outl(control, board->ctrl_base_addr + CTRL_STAT_OFFSET);    // verify that /INIT and DONE went low    status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET);    if (status & (DONE_MASK | _INIT_MASK)) {	THIS_ERR(            "FPGA did not reset: /INIT = %d, DONE = %d\n",	    (status & _INIT_MASK ? 1 : 0),            (status & DONE_MASK ? 1 : 0)        );	return -EIO;    }    // set /PROGRAM high, let FPGA come out of reset    control = status | _PROGRAM_MASK;    outl(control, board->ctrl_base_addr + CTRL_STAT_OFFSET);    // wait for /INIT to go high when it finishes clearing memory    // This should take no more than 100uS.  If we assume each PCI read    // takes 30nS (one PCI clock), that is 3300 reads.  Reads actually    // take several clocks, but even at a microsecond each, 3.3mS is not    // an excessive timeout value    {        int count = 3300;        do {            status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET);            if (status & _INIT_MASK) break;        } while (count-- > 0);        if (count == 0) {            THIS_ERR("FPGA did not come out of /INIT");            return -EIO;        }    }    return 0;}// fix up LASxBRD READY if neededstatic void hm2_plx9030_fixup_LASxBRD_READY(hm2_pci_t *board) {    hm2_lowlevel_io_t *this = &board->llio;    int offsets[] = { LAS0BRD_OFFSET, LAS1BRD_OFFSET, LAS2BRD_OFFSET, LAS3BRD_OFFSET };    int i;    for (i = 0; i < 4; i ++) {        u32 val;        int addr = board->ctrl_base_addr + offsets[i];        val = inl(addr);        if (!(val & LASxBRD_READY)) {            THIS_INFO("LAS%dBRD #READY is off, enabling now\n", i);            val |= LASxBRD_READY;            outl(val, addr);        }    }}static int hm2_plx9054_program_fpga(hm2_lowlevel_io_t *this, const bitfile_t *bitfile) {    hm2_pci_t *board = this->private;    int i;    u32 status;    // program the FPGA    for (i = 0; i < bitfile->e.size; i ++) {        outb(bitfile->e.data[i], board->data_base_addr);    }    // all bytes transferred, make sure FPGA is all set up now    for (i = 0; i < DONE_WAIT_5I22; i++) {        status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET_5I22);        if (status & DONE_MASK_5I22) break;    }    if (i >= DONE_WAIT_5I22) {        THIS_ERR("Error: Not /DONE; programming not completed.\n");        return -EIO;    }    return 0;}static int hm2_plx9054_reset(hm2_lowlevel_io_t *this) {    hm2_pci_t *board = this->private;    int i;    u32 status, control;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?