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

📄 ixxat_pci.c

📁 socket can driver, for s3c2440 using sja100, enjoy it!
💻 C
字号:
/* * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com> * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the version 2 of the GNU General Public License * as published by the Free Software Foundation * * 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/kernel.h>#include <linux/module.h>#include <linux/interrupt.h>#include <linux/netdevice.h>#include <linux/delay.h>#include <linux/pci.h>#include <linux/can.h>#include <linux/can/dev.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)#include <linux/io.h>#else#include <asm/io.h>#endif#include "sja1000.h"#define DRV_NAME  "ixxat_pci"MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");MODULE_DESCRIPTION("Socket-CAN driver for IXXAT PC-I 04/PCI PCI cards");MODULE_SUPPORTED_DEVICE("IXXAT PC-I 04/PCI card");MODULE_LICENSE("GPL v2");/* Maximum number of interfaces supported on one card. Currently * we only support a maximum of two interfaces, which is the maximum * of what Ixxat sells anyway. */#define IXXAT_PCI_MAX_CAN 2struct ixxat_pci {	struct pci_dev *pci_dev;	struct net_device *dev[IXXAT_PCI_MAX_CAN];	int conf_addr;	void __iomem *base_addr;};#define IXXAT_PCI_CAN_CLOCK  (16000000 / 2)#define IXXAT_PCI_OCR	     (OCR_TX0_PUSHPULL | OCR_TX0_INVERT | \			      OCR_TX1_PUSHPULL)#define IXXAT_PCI_CDR	     0#define CHANNEL_RESET_OFFSET 0x110#define CHANNEL_OFFSET      0x200#define INTCSR_OFFSET        0x4c /* Offset in PLX9050 conf registers */#define INTCSR_LINTI1        (1 << 0)#define INTCSR_LINTI2        (1 << 3)#define INTCSR_PCI           (1 << 6)/* PCI vender, device and sub-device ID */#define IXXAT_PCI_VENDOR_ID  0x10b5#define IXXAT_PCI_DEVICE_ID  0x9050#define IXXAT_PCI_SUB_SYS_ID 0x2540#define IXXAT_PCI_BASE_SIZE  0x400static struct pci_device_id ixxat_pci_tbl[] = {	{IXXAT_PCI_VENDOR_ID, IXXAT_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},	{0,}};MODULE_DEVICE_TABLE(pci, ixxat_pci_tbl);static u8 ixxat_pci_read_reg(struct net_device *ndev, int port){	u8 val;	val = readb((void __iomem *)(ndev->base_addr + port));	return val;}static void ixxat_pci_write_reg(struct net_device *ndev, int port, u8 val){	writeb(val, (void __iomem *)(ndev->base_addr + port));}static void ixxat_pci_del_chan(struct pci_dev *pdev, struct net_device *ndev){	dev_info(&pdev->dev, "Removing device %s\n", ndev->name);	unregister_sja1000dev(ndev);	free_sja1000dev(ndev);}static struct net_device *ixxat_pci_add_chan(struct pci_dev *pdev,		void __iomem *base_addr){	struct net_device *ndev;	struct sja1000_priv *priv;	int err;	ndev = alloc_sja1000dev(0);	if (ndev == NULL)		return ERR_PTR(-ENOMEM);	priv = netdev_priv(ndev);	ndev->base_addr = (unsigned long)base_addr;	priv->read_reg = ixxat_pci_read_reg;	priv->write_reg = ixxat_pci_write_reg;	priv->can.bittiming.clock = IXXAT_PCI_CAN_CLOCK;	priv->ocr = IXXAT_PCI_OCR;	priv->cdr = IXXAT_PCI_CDR;	/* Set and enable PCI interrupts */	ndev->irq = pdev->irq;	dev_dbg(&pdev->dev, "base_addr=%#lx irq=%d\n",			ndev->base_addr, ndev->irq);	SET_NETDEV_DEV(ndev, &pdev->dev);	err = register_sja1000dev(ndev);	if (err) {		dev_err(&pdev->dev, "Failed to register (err=%d)\n", err);		goto failure;	}	return ndev;failure:	free_sja1000dev(ndev);	return ERR_PTR(err);}static int __devinit ixxat_pci_init_one(struct pci_dev *pdev,				       const struct pci_device_id *ent){	struct ixxat_pci *board;	int err, intcsr = INTCSR_LINTI1 | INTCSR_PCI;	u16 sub_sys_id;	void __iomem *base_addr;	dev_info(&pdev->dev, "Initializing device %04x:%04x\n",	       pdev->vendor, pdev->device);	board = kzalloc(sizeof(*board), GFP_KERNEL);	if (!board)		return -ENOMEM;	err = pci_enable_device(pdev);	if (err)		goto failure;	err = pci_request_regions(pdev, DRV_NAME);	if (err)		goto failure;	err = pci_read_config_word(pdev, 0x2e, &sub_sys_id);	if (err)		goto failure_release_pci;	if (sub_sys_id != IXXAT_PCI_SUB_SYS_ID)		return -ENODEV;	/* Enable memory and I/O space */	err = pci_write_config_word(pdev, 0x04, 0x3);	if (err)		goto failure_release_pci;	board->conf_addr = pci_resource_start(pdev, 1);	base_addr = pci_iomap(pdev, 2, IXXAT_PCI_BASE_SIZE);	if (base_addr == 0) {		err = -ENODEV;		goto failure_release_pci;	}	board->base_addr = base_addr;	writeb(0x1, base_addr + CHANNEL_RESET_OFFSET);	writeb(0x1, base_addr + CHANNEL_OFFSET + CHANNEL_RESET_OFFSET);	udelay(100);	board->dev[0] = ixxat_pci_add_chan(pdev, base_addr);	if (IS_ERR(board->dev[0]))		goto failure_iounmap;	/* Check if second channel is available */	if ((readb(base_addr + CHANNEL_OFFSET + REG_MOD) & 0xa1) == 0x21 &&	    readb(base_addr + CHANNEL_OFFSET + REG_SR) == 0x0c &&	    readb(base_addr + CHANNEL_OFFSET + REG_IR) == 0xe0) {		board->dev[1] = ixxat_pci_add_chan(pdev,				base_addr + CHANNEL_OFFSET);		if (IS_ERR(board->dev[1]))			goto failure_unreg_dev0;		intcsr |= INTCSR_LINTI2;	}	/* enable interrupt(s) in PLX9050 */	outb(intcsr, board->conf_addr + INTCSR_OFFSET);	pci_set_drvdata(pdev, board);	return 0;failure_unreg_dev0:	ixxat_pci_del_chan(pdev, board->dev[0]);failure_iounmap:	pci_iounmap(pdev, board->base_addr);failure_release_pci:	pci_release_regions(pdev);failure:	kfree(board);	return err;}static void __devexit ixxat_pci_remove_one(struct pci_dev *pdev){	struct ixxat_pci *board = pci_get_drvdata(pdev);	int i;	/* Disable interrupts in PLX9050*/	outb(0, board->conf_addr + INTCSR_OFFSET);	for (i = 0; i < IXXAT_PCI_MAX_CAN; i++) {		if (!board->dev[i])			break;		ixxat_pci_del_chan(pdev, board->dev[i]);	}	pci_iounmap(pdev, board->base_addr);	pci_release_regions(pdev);	pci_disable_device(pdev);	pci_set_drvdata(pdev, NULL);	kfree(board);}static struct pci_driver ixxat_pci_driver = {	.name = DRV_NAME,	.id_table = ixxat_pci_tbl,	.probe = ixxat_pci_init_one,	.remove = __devexit_p(ixxat_pci_remove_one),};static int __init ixxat_pci_init(void){	return pci_register_driver(&ixxat_pci_driver);}static void __exit ixxat_pci_exit(void){	pci_unregister_driver(&ixxat_pci_driver);}module_init(ixxat_pci_init);module_exit(ixxat_pci_exit);

⌨️ 快捷键说明

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