?? isa_sja1000.c
字號(hào):
/* * isa_sja1000.c * Copyright (c) 2003 Kirill Smelkov <smelkov@mph1.phys.spbu.ru> * * ... BLURB ABOUT HARDWARE... * * 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. *//* * two words about prefixes: * board_ prefix marks routines assotiated with the whole board * isa_sja1000_ prefix marks routines assotiated with some chip on the board */#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/ioport.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,67)#include <linux/interrupt.h>#endif#include <asm/io.h>#include "trace.h"#include "canbus4linux.h"#include "isa_sja1000.h"#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifstruct io_info { unsigned long io_base; unsigned long io_len;};struct board_info { const char *name; int io_irq; // irq line long Fosc; // oscillator frequency u8 OCR; // OCR (output control register) value specific for board int nchips; struct io_info io_info[MAXCHIPS];};static const struct board_info boards_list[] = {// name irq Fosc, OCR, nchips {io_base, io_len} for each chip{ "can-200pc", 5, 16000000, 0x1b, 2, { {0x100, 0x20}, {0x120, 0x20} } },// next two are for testing{ "c200-1", 5, 16000000, 0x1b, 1, { {0x100, 0x20} } }, // first channel of can-200pc{ "c200-2", 5, 16000000, 0x1b, 1, { {0x120, 0x20} } }, // second channel of can-200pc{ NULL }};// find specified board in the liststatic int find_board(const char * name){ int i=0; while (boards_list[i].name) { if ( !strcmp(name, boards_list[i].name) ) return i; ++i; } return -1;}#define MAXBOARDS 2static ISA_SJA1000_BOARD devices[MAXBOARDS];// *******************// * REGISTER ACCESS *// *******************static void isa_sja1000_writereg(void * data, u8 reg, u8 val){ ISA_SJA1000_CHIP * self = (ISA_SJA1000_CHIP *) data; TRACE("writereg(0x%2.2x,0x%2.2x)", reg, val); outb(val, self->io_base + reg);}static u8 isa_sja1000_readreg(void * data, u8 reg){ ISA_SJA1000_CHIP * self = (ISA_SJA1000_CHIP *) data; u8 val; val = inb(self->io_base + reg); TRACE("readreg(0x%2.2x) = 0x%2.2x", reg, val); return val;}// *** ?unneeded? _reset routines.../*static inline void isa_sja1000_reset_mode(ISA_SJA1000_CHIP * self){ u8 val = inb(self->io_base + 0); u8 CR = val | 0x01; int tries=100; while ( !(val & 0x01)) { outb_p(CR, self->io_base + 0); val = inb(self->io_base + 0); if (--tries == 0) { TRACE("can't reset sja1000... XXX: ?what can i do here?"); break; } };}static inline void isa_sja1000_operating_mode(ISA_SJA1000_CHIP * self){ u8 val = inb(self->io_base + 0); u8 CR = val & 0x3e; // ? 1e int tries=100; while (val & 0x01) { outb_p(CR, self->io_base + 0); val = inb(self->io_base + 0); if (--tries == 0) { TRACE("can't put sja1000 into operating mode... XXX: ?what can i do here?"); break; } }}static void isa_sja1000_writereg_reset(void * data, u8 reg, u8 val){ ISA_SJA1000_CHIP * self = (ISA_SJA1000_CHIP *) data; TRACE("DEPRECATED!"); TRACE("writereg_reset(0x%2.2x,0x%2.2x)", reg, val); isa_sja1000_reset_mode(self); outb(val, self->io_base + reg); isa_sja1000_operating_mode(self);}static u8 isa_sja1000_readreg_reset(void * data, u8 reg){ ISA_SJA1000_CHIP * self = (ISA_SJA1000_CHIP *) data; u8 ret; isa_sja1000_reset_mode(self); ret = inb(self->io_base + reg); isa_sja1000_operating_mode(self); TRACE("DEPRECATED!"); TRACE("readreg_reset(0x%2.2x) = 0x%2.2x", reg, ret); return ret;}*/// ****************// * IRQ HANDLING *// ****************static int isa_sja1000_register_isr(void * data, sja1000_isr chip_isr, struct sja1000_admin * chip_isr_data){ ISA_SJA1000_CHIP * self = (ISA_SJA1000_CHIP *) data; TRACE("register_isr()"); if (!self) return -EINVAL; self->chip_isr = chip_isr; self->chip_isr_data = chip_isr_data; return 0;}static int isa_sja1000_unregister_isr(void * data){ ISA_SJA1000_CHIP * self = (ISA_SJA1000_CHIP *) data; TRACE("unregister_isr()"); if (!self) return -EINVAL; self->chip_isr = 0; self->chip_isr_data = 0; return 0;}// the whole board interrupt service routine#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4)static irqreturn_t board_isr(int irq, void * dev_id, struct pt_regs * regs)#elsestatic void board_isr(int irq, void * dev_id, struct pt_regs * regs)#endif{ ISA_SJA1000_BOARD * self = (ISA_SJA1000_BOARD *) dev_id; unsigned int i; TRACE("isr()"); if (!self)#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4) return IRQ_NONE;#else return;#endif for (i=0;i<self->nchips;++i) if (self->chips[i].chip_isr) self->chips[i].chip_isr(&self->chips[i],self->chips[i].chip_isr_data);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4) return IRQ_HANDLED;#else return;#endif}// *****************// * OPEN & CLOSE *// *****************static int isa_sja1000_open(void * data){ ISA_SJA1000_CHIP * self = (ISA_SJA1000_CHIP *) data; int err; TRACE("open()");// spin_lock(&self->lock); do { if (self->open) { err = -EBUSY; break; } self->open++; // NOTE: this is currently specific for my card (the wierd thing) // hardware reset is made via isa_sja1000_writereg(self, 0x1e, 0x00); // reset } while (0);// spin_unlock(&self->lock); return 0;}static int isa_sja1000_close(void * data){// ISA_SJA1000_CHIP * self = (ISA_SJA1000_CHIP *) data; TRACE("close()"); return 0;}char * cards[MAXBOARDS];MODULE_PARM(cards,"1-" __MODULE_STRING(MAXBOARDS) "s");MODULE_PARM_DESC(cards, "specify (comma separated) CAN board models");// *************************// * MODULE INIT & CLEANUP *// *************************void __exit isa_sja1000_cleanup(void);int __init isa_sja1000_init(void){ int err=-ENODEV; int num, i, minor; int cards_idx[MAXBOARDS]; TRACE("init()"); if (!cards[0]) { TRACE("you have to specify your card (cards parameter). giving up."); return -ENODEV; } for (num=0;num<MAXBOARDS;++num) { if (!cards[num]) { cards_idx[num] = -1; break; } err = find_board(cards[num]); if (err==-1) { TRACE("card '%s' is not suppoprted.", cards[num]); return -ENODEV; } cards_idx[num] = err; } for (num=0,minor=0; (cards_idx[num]!=-1 && num<MAXBOARDS) ;++num) { ISA_SJA1000_BOARD * dev = &devices[num]; const struct board_info * idev = &boards_list[cards_idx[num]]; unsigned int io_irq; struct sja1000_access access = { pOpenCanDevice: isa_sja1000_open, pCloseCanDevice: isa_sja1000_close, pWriteToRegister: isa_sja1000_writereg, pReadFromRegister: isa_sja1000_readreg, pRegisterIsr: isa_sja1000_register_isr, pUnregisterIsr: isa_sja1000_unregister_isr, bCanChipsetFlags: CANBUS_CFS_CAN_2_0_B | CANBUS_CFS_EXT_FRAME, chipset_frequency: idev->Fosc, output_control_register: idev->OCR }; // io for all chips an the board TRACE("requesting io..."); for (i=0;i<idev->nchips;++i) { ISA_SJA1000_CHIP * chip = &dev->chips[i]; unsigned long io_base; unsigned long io_len; snprintf(chip->name, MAX_DEVICE_NAME_LENGTH, "%s[%i]", idev->name, i); chip->num = -1; chip->lock = SPIN_LOCK_UNLOCKED; dev->nchips++; io_base = idev->io_info[i].io_base; io_len = idev->io_info[i].io_len; if (!request_region(io_base, io_len, chip->name)) { TRACE("request_region(%lx,%lx) failed", io_base, io_len); err=-EBUSY; goto out; } chip->io_base = io_base; chip->io_len = io_len; ++minor; } // irq for the board io_irq = idev->io_irq; TRACE("requesting irq..."); err = request_irq(io_irq, board_isr, 0 /* flags */, "isacan", dev); if (err) { TRACE("request_irq(%i) failed", io_irq); goto out; } dev->io_irq = io_irq; // register every chip on the board in the canbus4linux subsystem for (i=0;i<dev->nchips;++i) { ISA_SJA1000_CHIP * chip = &dev->chips[i]; TRACE("%s: registering device no.: %i ...", idev->name, i); chip->num = sja1000_register_device(chip->name, CANBUS4LINUX_VERSION, chip, &access, 0, minor); if (chip->num == -1) { TRACE("sja1000_register_device() failed"); err = -ENOMEM; goto out; // not enough memory to register this device } } err = 0; }out: if (err) isa_sja1000_cleanup(); return err;}void __exit isa_sja1000_cleanup(void){ int num, i; TRACE("cleanup()"); for (num=0;num<MAXBOARDS;++num) { ISA_SJA1000_BOARD * dev = &devices[num]; if (!dev->nchips) continue; for (i=0; i<dev->nchips; ++i) { ISA_SJA1000_CHIP * chip = &dev->chips[i]; if (chip->num!=-1) chip->num = sja1000_unregister_device(chip->num); } if (dev->io_irq) free_irq(dev->io_irq, dev); for (i=0; i<dev->nchips; ++i) { ISA_SJA1000_CHIP * chip = &dev->chips[i]; if (chip->io_base) release_region(chip->io_base, chip->io_len); } }}module_init(isa_sja1000_init);module_exit(isa_sja1000_cleanup);MODULE_AUTHOR("Kirill Smelkov <smelkov@mph1.phys.spbu.ru>");MODULE_DESCRIPTION("CAN driver for generic SJA1000 based ISA card");// vim: ts=4
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -