⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtcan_peak_pci.c

📁 Peak-CAN控制器(PCI接口)的驱动程序
💻 C
字号:
/* * Copyright (C) 2006 Wolfgang Grandegger <wg@grandegger.com> * * Derived from the PCAN project file driver/src/pcan_pci.c: * * Copyright (C) 2001-2006  PEAK System-Technik GmbH * * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <linux/module.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/pci.h>#include <asm/io.h>#include <rtdm/rtdm_driver.h>/* CAN device profile */#include <rtdm/rtcan.h>#include <rtcan_dev.h>#include <rtcan_raw.h>#include <rtcan_sja1000.h>#include <rtcan_sja1000_regs.h>#define RTCAN_DEV_NAME    "rtcan%d"#define RTCAN_DRV_NAME    "PEAK-PCI-CAN"static char *peak_pci_board_name = "PEAK-PCI";MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");MODULE_DESCRIPTION("RTCAN board driver for PEAK-PCI cards");MODULE_SUPPORTED_DEVICE("PEAK-PCI card CAN controller");MODULE_LICENSE("GPL");struct rtcan_peak_pci{    struct pci_dev *pci_dev;     struct rtcan_device *slave_dev;    int channel;    volatile void __iomem *base_addr;      volatile void __iomem *conf_addr;};#define PEAK_PCI_CAN_SYS_CLOCK (16000000 / 2)#define PELICAN_SINGLE  (SJA_CDR_CAN_MODE | SJA_CDR_CBP | 0x07 | SJA_CDR_CLK_OFF)#define PELICAN_MASTER  (SJA_CDR_CAN_MODE | SJA_CDR_CBP | 0x07            )#define PELICAN_DEFAULT (SJA_CDR_CAN_MODE                                 )#define CHANNEL_SINGLE 0 /* this is a single channel device */#define CHANNEL_MASTER 1 /* multi channel device, this device is master */#define CHANNEL_SLAVE  2 /* multi channel device, this is slave */// important PITA registers#define PITA_ICR         0x00        // interrupt control register#define PITA_GPIOICR     0x18        // general purpose IO interface control register#define PITA_MISC        0x1C        // miscellanoes register#define PEAK_PCI_VENDOR_ID   0x001C  // the PCI device and vendor IDs#define PEAK_PCI_DEVICE_ID   0x0001#define PCI_CONFIG_PORT_SIZE 0x1000  // size of the config io-memory#define PCI_PORT_SIZE        0x0400  // size of a channel io-memorystatic struct pci_device_id peak_pci_tbl[] = {	{PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},};MODULE_DEVICE_TABLE (pci, peak_pci_tbl);static u8 rtcan_peak_pci_read_reg(struct rtcan_device *dev, int port){    struct rtcan_peak_pci *board = (struct rtcan_peak_pci *)dev->board_priv;    return readb(board->base_addr + ((unsigned long)port << 2));}static void rtcan_peak_pci_write_reg(struct rtcan_device *dev, int port, u8 data){    struct rtcan_peak_pci *board = (struct rtcan_peak_pci *)dev->board_priv;    writeb(data, board->base_addr + ((unsigned long)port << 2));}static void rtcan_peak_pci_irq_ack(struct rtcan_device *dev){    struct rtcan_peak_pci *board = (struct rtcan_peak_pci *)dev->board_priv;    u16 pita_icr_low;    /* Select and clear in Pita stored interrupt */    pita_icr_low = readw(board->conf_addr + PITA_ICR);    if (board->channel == CHANNEL_SLAVE) {	if (pita_icr_low & 0x0001)	    writew(0x0001, board->conf_addr + PITA_ICR);    }     else {	if (pita_icr_low & 0x0002)	    writew(0x0002, board->conf_addr + PITA_ICR);    }}static void rtcan_peak_pci_del_chan(struct rtcan_device *dev, 				    int init_step){    struct rtcan_peak_pci *board;    u16 pita_icr_high;    if (!dev)	return;    board = (struct rtcan_peak_pci *)dev->board_priv;    switch (init_step) {    case 0:			/* Full cleanup */	printk("Removing %s %s device %s\n", 	       peak_pci_board_name, dev->ctrl_name, dev->name);	rtcan_sja1000_unregister(dev);    case 5: 	pita_icr_high = readw(board->conf_addr + PITA_ICR + 2);	if (board->channel == CHANNEL_SLAVE) {	    pita_icr_high &= ~0x0001;	} else {	    pita_icr_high &= ~0x0002;	}	writew(pita_icr_high, board->conf_addr + PITA_ICR + 2);     case 4:	iounmap((void *)board->base_addr);    case 3:	if (board->channel != CHANNEL_SLAVE)	    iounmap((void *)board->conf_addr);    case 2:        rtcan_dev_free(dev);	    case 1:	break;    }}static int rtcan_peak_pci_add_chan(struct pci_dev *pdev, int channel, 				   struct rtcan_device **master_dev){    struct rtcan_device *dev;    struct rtcan_sja1000 *chip;    struct rtcan_peak_pci *board;    u16 pita_icr_high;    unsigned long addr;    int ret, init_step = 1;    dev = rtcan_dev_alloc(sizeof(struct rtcan_sja1000),			  sizeof(struct rtcan_peak_pci));    if (dev == NULL)        return -ENOMEM;    init_step = 2;        chip = (struct rtcan_sja1000 *)dev->priv;    board = (struct rtcan_peak_pci *)dev->board_priv;    board->pci_dev = pdev;    board->channel = channel;    if (channel != CHANNEL_SLAVE) {	addr = pci_resource_start(pdev, 0);    	board->conf_addr = ioremap(addr, PCI_CONFIG_PORT_SIZE); 	if (board->conf_addr == 0) {	    ret = -ENODEV;	    goto failure;	}	init_step = 3;    	/* Set GPIO control register */	writew(0x0005, board->conf_addr + PITA_GPIOICR + 2);      	if (channel == CHANNEL_MASTER)	    writeb(0x00, board->conf_addr + PITA_GPIOICR); /* enable both */	else	    writeb(0x04, board->conf_addr + PITA_GPIOICR); /* enable single */		writeb(0x05, board->conf_addr + PITA_MISC + 3);  /* toggle reset */	mdelay(5);	writeb(0x04, board->conf_addr + PITA_MISC + 3);  /* leave parport mux mode */		    } else {	struct rtcan_peak_pci *master_board = 	    (struct rtcan_peak_pci *)(*master_dev)->board_priv;	master_board->slave_dev = dev;	board->conf_addr = master_board->conf_addr;    }    addr = pci_resource_start(pdev, 1);        if (channel == CHANNEL_SLAVE)	addr += 0x400;        board->base_addr = ioremap(addr, PCI_PORT_SIZE);     if (board->base_addr == 0) {	ret = -ENODEV;	goto failure;    }    init_step = 4;    dev->board_name = peak_pci_board_name;    chip->read_reg = rtcan_peak_pci_read_reg;    chip->write_reg = rtcan_peak_pci_write_reg;    chip->irq_ack = rtcan_peak_pci_irq_ack;    /* Clock frequency in Hz */    dev->can_sys_clock = PEAK_PCI_CAN_SYS_CLOCK;    /* Output control register */    chip->ocr = SJA_OCR_MODE_NORMAL | SJA_OCR_TX0_PUSHPULL;    /* Clock divider register */    if (channel == CHANNEL_MASTER)	chip->cdr = PELICAN_MASTER;    else	chip->cdr = PELICAN_SINGLE;    strncpy(dev->name, RTCAN_DEV_NAME, IFNAMSIZ);    /* Register and setup interrupt handling */#ifdef CONFIG_XENO_OPT_SHIRQ_LEVEL    chip->irq_flags = RTDM_IRQTYPE_SHARED;#else    chip->irq_flags = 0;#endif    chip->irq_num = pdev->irq;    pita_icr_high = readw(board->conf_addr + PITA_ICR + 2);    if (channel == CHANNEL_SLAVE) {	pita_icr_high |= 0x0001;    } else {	pita_icr_high |= 0x0002;    }    writew(pita_icr_high, board->conf_addr + PITA_ICR + 2);     init_step = 5;	    printk("%s: base_addr=%p conf_addr=%p irq=%d\n", RTCAN_DRV_NAME, 	   board->base_addr, board->conf_addr, chip->irq_num);    /* Register SJA1000 device */    ret = rtcan_sja1000_register(dev);    if (ret) {	printk(KERN_ERR "ERROR while trying to register SJA1000 device %d!\n",	       ret);	goto failure;    }        if (channel != CHANNEL_SLAVE)	*master_dev = dev;    return 0; failure:    rtcan_peak_pci_del_chan(dev, init_step);    return ret;}static int __devinit peak_pci_init_one (struct pci_dev *pdev,					const struct pci_device_id *ent){    int ret;    u16 sub_sys_id;    struct rtcan_device *master_dev = NULL;    printk("%s: initializing device %04x:%04x\n",	   RTCAN_DRV_NAME,  pdev->vendor, pdev->device);    if ((ret = pci_enable_device (pdev)))	goto failure;    if ((ret = pci_request_regions(pdev, RTCAN_DRV_NAME)))	goto failure;    if ((ret = pci_read_config_word(pdev, 0x2e, &sub_sys_id)))	goto failure_cleanup;        /* Enable memory space */    if ((ret = pci_write_config_word(pdev, 0x04, 2)))	goto failure_cleanup;        if ((ret = pci_write_config_word(pdev, 0x44, 0)))	goto failure_cleanup;        if (sub_sys_id > 3) {	if ((ret = rtcan_peak_pci_add_chan(pdev, CHANNEL_MASTER, 					   &master_dev)))	    goto failure_cleanup;#ifdef CONFIG_XENO_OPT_SHIRQ_LEVEL	if ((ret = rtcan_peak_pci_add_chan(pdev, CHANNEL_SLAVE, 					   &master_dev)))	    goto failure_cleanup;#else	printk("Shared interrupts not enabled, using single channel!\n");#endif    } else {	if ((ret = rtcan_peak_pci_add_chan(pdev, CHANNEL_SINGLE,					   &master_dev)))	    goto failure_cleanup;    }    pci_set_drvdata(pdev, master_dev);    return 0; failure_cleanup:    if (master_dev)	rtcan_peak_pci_del_chan(master_dev, 0);    pci_release_regions(pdev);     failure:    return ret;	}static void __devexit peak_pci_remove_one (struct pci_dev *pdev){    struct rtcan_device *dev = pci_get_drvdata(pdev);    struct rtcan_peak_pci *board = (struct rtcan_peak_pci *)dev->board_priv;    if (board->slave_dev)	rtcan_peak_pci_del_chan(board->slave_dev, 0);    rtcan_peak_pci_del_chan(dev, 0);    pci_release_regions(pdev);    pci_disable_device(pdev);    pci_set_drvdata(pdev, NULL);}static struct pci_driver rtcan_peak_pci_driver = {	.name		= RTCAN_DRV_NAME,	.id_table	= peak_pci_tbl,	.probe		= peak_pci_init_one,	.remove		= __devexit_p(peak_pci_remove_one),};static int __init rtcan_peak_pci_init(void){    return pci_module_init(&rtcan_peak_pci_driver);}static void __exit rtcan_peak_pci_exit(void){    pci_unregister_driver(&rtcan_peak_pci_driver);}module_init(rtcan_peak_pci_init);module_exit(rtcan_peak_pci_exit);

⌨️ 快捷键说明

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