📄 elektor_canpar.c
字号:
/* * elektor_canpar.c * Copyright (c) 2001 J黵gen Eder <Juergen.Eder@gmx.de> * * The hardware driver for the Elektor CAN Card * for the parallel port <http://www.elektor.de>. The circuit was * in magazine: June 2000 * * 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. *///#define EXPORT_SYMTAB#include <linux/version.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/parport.h>#include <linux/ioctl.h>#include <asm/uaccess.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,18)#include <linux/spinlock.h>#else#include <asm/spinlock.h>#endif#include <linux/delay.h>#include <linux/time.h>#include "trace.h"#include "canbus4linux.h"#include "elektor_canpar.h"#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifstatic int minimum_num=-1;static int maximum_num=-1;static CANPARDEVICE candevice[PARPORT_MAX];static struct parport_driver ParportDriver;static void wr_can(PCANPARDEVICE lpDIOCParms, unsigned char adr,unsigned char wert);static unsigned char rd_can(PCANPARDEVICE lpDIOCParms, unsigned char adr);static void out2Data(PCANPARDEVICE lpDIOCParms, int data);static void out2Controlport(PCANPARDEVICE lpDIOCParms, int data);static unsigned char inControlport(PCANPARDEVICE lpDIOCParms);static unsigned char inData(PCANPARDEVICE lpDIOCParms);//static void MaskIRQ(PCANPARDEVICE lpDIOCParms);//static void UnmaskIRQ(PCANPARDEVICE lpDIOCParms);//static void out2ECPControlport(PCANPARDEVICE lpDIOCParms, int data);//static unsigned char inECPControlport(PCANPARDEVICE lpDIOCParms);//static unsigned char inStatusport(PCANPARDEVICE lpDIOCParms);/***************************************************************************************/static void wr_can(PCANPARDEVICE lpDIOCParms, unsigned char adr,unsigned char wert) // Wert in Register des 82C200 an Adresse adr schreiben{ out2Controlport(lpDIOCParms,lpDIOCParms->statusport & ~0x20); // Datenport auf Ausgang schalten out2Data(lpDIOCParms,adr); // Adresse auf Datenport out2Controlport(lpDIOCParms,lpDIOCParms->statusport | 0x08); // ALE=0 out2Data(lpDIOCParms,wert); // Wert auf Datenport out2Controlport(lpDIOCParms,lpDIOCParms->statusport | 0x02); // WR\=0 out2Controlport(lpDIOCParms,lpDIOCParms->statusport & ~0x02); // WR\=1 out2Controlport(lpDIOCParms,lpDIOCParms->statusport & ~0x08); // ALE=1 out2Controlport(lpDIOCParms,lpDIOCParms->statusport | 0x20); // Datenport auf Eingang}/***************************************************************************************/static unsigned char rd_can(PCANPARDEVICE lpDIOCParms, unsigned char adr) // Wert aus Register des 82C200 auslesen{ unsigned char bw; out2Controlport(lpDIOCParms,lpDIOCParms->statusport & ~0x20); // Datenport auf Ausgang out2Data(lpDIOCParms,adr); // Adresse auf Datenport out2Controlport(lpDIOCParms,lpDIOCParms->statusport | 0x08); // ALE=0 out2Controlport(lpDIOCParms,lpDIOCParms->statusport | 0x20); // Datenport auf Eingang out2Controlport(lpDIOCParms,lpDIOCParms->statusport & ~0x04); // RD\=0 bw=inData(lpDIOCParms); // Datenport auslesen out2Controlport(lpDIOCParms,lpDIOCParms->statusport | 0x04); // RD\=1 out2Controlport(lpDIOCParms,lpDIOCParms->statusport & ~0x08); // ALE=1; return(bw);}/***************************************************************************************//*static unsigned char inStatusport(PCANPARDEVICE lpDIOCParms){ return parport_read_status(lpDIOCParms->parport->port);} *//***************************************************************************************/static void out2Controlport(PCANPARDEVICE lpDIOCParms, int data){ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) parport_write_control(lpDIOCParms->parport->port,data & ~0x20); if(data & 0x20) parport_data_reverse(lpDIOCParms->parport->port); else parport_data_forward(lpDIOCParms->parport->port);#else parport_write_control(lpDIOCParms->parport->port,data);#endif lpDIOCParms->statusport = data;} /***************************************************************************************/static unsigned char inControlport(PCANPARDEVICE lpDIOCParms){ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) return lpDIOCParms->statusport;#else return parport_read_control(lpDIOCParms->parport->port);#endif} /***************************************************************************************/static void out2Data(PCANPARDEVICE lpDIOCParms, int data){ parport_write_data(lpDIOCParms->parport->port,data);} /***************************************************************************************/static unsigned char inData(PCANPARDEVICE lpDIOCParms){ return parport_read_data(lpDIOCParms->parport->port);} /***************************************************************************************/#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static void out2ECPControlport(PCANPARDEVICE lpDIOCParms, int data){ parport_write_econtrol(lpDIOCParms->parport->port,data);} #endif/***************************************************************************************/#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static unsigned char inECPControlport(PCANPARDEVICE lpDIOCParms){ return parport_read_econtrol(lpDIOCParms->parport->port);} #endif /***************************************************************************************/static int can_preempt(void *handle){ return 1; // 1=don't release parport}/***************************************************************************************/static void can_irq(int irq, void *dev_id, struct pt_regs *regs){ PCANPARDEVICE parport=(PCANPARDEVICE)dev_id; TRACE("can_irq()"); if(parport && parport->pIsr) { // Aufruf der SJA Routine (*parport->pIsr)(parport,parport->pSja1000Par); }}/***************************************************************************************/static int canpar_register_isr(PCANPARDEVICE lpDIOCParms, sja1000_isr pIsr, struct sja1000_admin *pSja1000Par){ TRACE("registering isr()"); if(lpDIOCParms) { lpDIOCParms->pIsr = pIsr; lpDIOCParms->pSja1000Par = pSja1000Par; return 0; } return -EINVAL;}/***************************************************************************************/static int canpar_unregister_isr(PCANPARDEVICE lpDIOCParms){ TRACE("unregistering isr()"); if(lpDIOCParms) { lpDIOCParms->pIsr = 0; return 0; } return -EINVAL;}/***************************************************************************************/static int canpar_open_device(PCANPARDEVICE lpDIOCParms){ TRACE("open device"); if(lpDIOCParms) { if(parport_claim(lpDIOCParms->parport)) { TRACE("no access to PARPORT device"); return -ENODEV; } lpDIOCParms->ecp = 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) if(lpDIOCParms->parport->port->modes & (PARPORT_MODE_PCECP+PARPORT_MODE_PCECPEPP+PARPORT_MODE_PCECPPS2)) { TRACE("using ECP mode"); lpDIOCParms->ecp = 1; } else { TRACE("using Standard mode (Bidirectional, EPP)"); lpDIOCParms->ecp = 0; }#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) out2Controlport(lpDIOCParms,0x04); // Schnittstelle initialisieren parport_enable_irq(lpDIOCParms->parport->port);#else if (lpDIOCParms->ecp == 1) // ECP Modus umschalten out2ECPControlport(lpDIOCParms,inECPControlport(lpDIOCParms)|0x20); out2Controlport(lpDIOCParms,0x14); // Schnittstelle initialisieren/IRQ ein#endif lpDIOCParms->open = 1; return 0; } TRACE("Invalid data or no parport"); return -ENODEV;}/***************************************************************************************/static int canpar_close_device(PCANPARDEVICE lpDIOCParms){ TRACE("close device"); if(lpDIOCParms) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) out2Controlport(lpDIOCParms,inControlport(lpDIOCParms)&0xef); // Schnittstelle: IRQ aus parport_disable_irq(lpDIOCParms->parport->port);#else out2Controlport(lpDIOCParms,inControlport(lpDIOCParms)&0xef); // Schnittstelle: IRQ aus#endif parport_release(lpDIOCParms->parport); lpDIOCParms->open = 0; } return 0;}/***************************************************************************************/static void cb_canpar_attach(struct parport *port){ // Search a free entry int num; for(num=0;num < PARPORT_MAX; num++) { if(candevice[num].parport == 0) { candevice[num].open = 0; candevice[num].pIsr = 0; candevice[num].num = num; candevice[num].parport = parport_register_device(port, "elektor_canpar", can_preempt, NULL, can_irq,0,&candevice[num]); if (!candevice[num].parport) { TRACE("Can't register device no.: %d name: %s",num, port->name); } else { struct sja1000_access access; char name[MAX_DEVICE_NAME_LENGTH]; TRACE("Register device no.: %d",num); access.chipset_frequency = 16000000; access.output_control_register = 0xc2; access.pOpenCanDevice = (sja1000_openCanDevice)canpar_open_device; access.pCloseCanDevice = (sja1000_closeCanDevice)canpar_close_device; access.pWriteToRegister = (sja1000_writeToRegister)wr_can; access.pReadFromRegister = (sja1000_readFromRegister)rd_can; access.pRegisterIsr = (sja1000_registerIsr)canpar_register_isr; access.pUnregisterIsr = (sja1000_unregisterIsr)canpar_unregister_isr; access.bCanChipsetFlags=CANBUS_CFS_CAN_2_0_A+CANBUS_CFS_CAN_2_0_B+CANBUS_CFS_EXT_FRAME; sprintf(name,"elektor parallelport card%d",num); candevice[num].num = sja1000_register_device(name, CANBUS4LINUX_VERSION, &candevice[num], &access, minimum_num, maximum_num); if(candevice[num].num < 0) break; // not enough memory to register this device } break; } }}/***************************************************************************************/static void cb_canpar_detach(struct parport *port){ int num; for(num=0;num < PARPORT_MAX; num++) { if(candevice[num].parport && (candevice[num].parport->port == port)) { TRACE("cb_canpar_detach: %d name: %s",num, port->name); parport_unregister_device(candevice[num].parport); return; } } INFO_TRACE("Can't detach parport: parport not found in candevice list %d: %s",num, port->name);}/***************************************************************************************/int init_module(void){ #ifdef EXPORT_NO_SYMBOLS EXPORT_NO_SYMBOLS;#endif TRACE("init_module()"); memset(candevice,0x00,PARPORT_MAX*sizeof(CANPARDEVICE)); memset(&ParportDriver,0x00,sizeof(struct parport_driver)); ParportDriver.name = "elektor_canpar"; ParportDriver.attach = cb_canpar_attach; ParportDriver.detach = cb_canpar_detach; if (0 != parport_register_driver(&ParportDriver)) { INFO_TRACE("Error while calling parport_register_driver()"); } TRACE("Init module finished"); return 0;}/***************************************************************************************/void cleanup_module(void){ int num; TRACE("cleanup"); for(num=0; num < PARPORT_MAX; num++) { if (candevice[num].parport) { TRACE("Unregister device no.: %d",num); if(candevice[num].open) canpar_close_device(&candevice[num]); candevice[num].num = sja1000_unregister_device(candevice[num].num); } } parport_unregister_driver(&ParportDriver); candevice[num].parport = 0;}/***************************************************************************************/MODULE_PARM(minimum_num,"1i");MODULE_PARM(maximum_num,"1i");MODULE_AUTHOR("Juergen Eder <Juergen.Eder@gmx.de>");MODULE_DESCRIPTION("CAN driver for Elektor CAN Card 6/2000");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -