www.pudn.com > canbus4linux.rar > canbuscore.c
/* * canbuscore.c * Copyright (c) 2001 Jürgen Eder* * A general canbus driver. To use this, you need also a * hardware driver (for example: sja1000.o + can200par.o). * Tested under Linux 2.4.20 on i386 PC architecture. * * installation: * * make all * make install * * char-major numbers up to 240 are "LOCAL/EXPERIMENTAL" (see /usr/src/linux/Documentation/devices.txt) * char-major 91 is reserved for CAN BUS * insert following lines into /etc/modules.conf: * * only ELEKTOR CAN Card * -------------------------------------------------- * alias char-major-91 elektor_canpar * * * or only CAN200 Card * -------------------------------------------------- * alias char-major-91 can200par * * * or both CAN Cards (kernel < 2.4.0) * -------------------------------------------------- * alias char-major-91 elektor_canpar * post-install elektor_canpar /sbin/modprobe "-k" can200par * * * or both CAN Cards (kernel >= 2.4.0, this also work with 2.2.x) * -------------------------------------------------- * alias char-major-91 canbus * probeall canbus elektor_canpar can200par * -------------------------------------------------- * * Also set the IRQ for the parport driver * for example (IRQ 7 for LPT1): * -------------------------------------------------- * options parport_pc io=0x378 irq=7,none * -------------------------------------------------- * * After changing "modules.conf" do a "depmod -a" * * Kernel > 2.5 need a "generate-modprobe.conf" * * Reload the parport driver: * rmmod parport_pc * modprobe parport_pc io=0x378 irq=7 * * * 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 #define CANBUS4LINUX_CLEARTEXT_COMMANDS #include #include #include #include #include #include #include #include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,67) #include #include #endif #include "trace.h" #include "canbus4linux.h" #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); #endif static int major=91; static int virtualize=1; static char *version = "0.2.1"; #define CANBUS4LINUX_PROC_DIR "canbus" #define NUM_CANBUS_DEVICES 10 #define MAX_DEVICE_INFO (2*MAX_DEVICE_NAME_LENGTH) #define NUMBER_OF_WRITE_BUFFER (100) #define MAX_EVENTS (2*NUMBER_OF_WRITE_BUFFER) int canbus4linux_fasync(int fd, struct file *file, int mode); void *Allocate_Memory(unsigned long s); void Free_Memory(void *p); struct canbus_time GetTime(void); static struct canbus_admin canbus4linux_admin[NUM_CANBUS_DEVICES]; static struct proc_dir_entry *canbus4linux_proc_dir=NULL; struct canbus_intern_transmit { struct canbus_transmit_data data; struct file *fa_file; }; struct proc_registers { struct canbus_admin *pAdmin; u16 register_nr; }; struct canbus_file; struct canbus_admin { /* W I C H T I G * Bei Änderungen muß evtl. auch "canbus4linux_register_device()" * geändert werden */ struct canbus_access access; int driver_registered; void *pDeviceParm; char cDeviceName[MAX_DEVICE_INFO]; int bCan_2B; // 0=CAN 2.0 A 1=CAN 2.0B int bFrameFmt; // 0=11 bit if CAN 2.0A and 29 bit if CAN 2.0B, 1=always 11 bit, 2=always 29bit (see: CANBUS_TRANS_...) int bOpen; unsigned long iBaudrate; struct canbus_acceptance_filter acceptance_filter; // hardwarefilter struct canbus_acceptance_filter soft_acceptance_filter; // softwarefilter int standby; int virtualize; unsigned long lost; int busload; short transmitting; // 1=Daten wurden in das SJA1000 geschrieben, warte jetzt auf IRQ struct canbus_properties props; struct canbus_file *cf_first; struct fasync_struct *async_queue; struct proc_dir_entry *proc_dir; struct proc_dir_entry *proc_register_dir; struct proc_registers *proc_regs; struct canbus_intern_transmit send_data; struct canbus_intern_transmit *sndISRInfo; // CAN-Botschaften in der Warteschlange, die noch an den SJA übergeben werden müssen (FIFO) volatile short sndIn; // Nummer (Daten wurden in die Warteschlange eingereiht) volatile short sndOut; // Nummer (bis "hier" wurden die Daten bereits abgeholt) }; struct canbus_file { struct canbus_file *next; struct file *file; struct canbus_admin *adm; char write_buffer[NUMBER_OF_WRITE_BUFFER]; int write_buffer_pos; int sleeping_send_wait; int sleeping_send_read; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) wait_queue_head_t sended; wait_queue_head_t send_wait; wait_queue_head_t send_read; #else struct wait_queue *sended; struct wait_queue *send_wait; struct wait_queue *send_read; #endif int send_counter; struct canbus_event *admISRInfo; // Daten, die an die USER-Mode Applikation übergeben werden (FIFO-Struktur) short admIn; // Nummer (Daten wurden in die Warteschlange eingereiht) short admOut; // Nummer (bis "hier" wurden die Daten bereits abgeholt) }; /***************************************************************************************/ int canbus4linux_open_device(struct canbus_admin *pPar) { int ret=0; TRACE("canbus4linux_open_device -1- %d",pPar->bOpen); if(!pPar->bOpen) { TRACE("canbus4linux_open_device -2-"); pPar->transmitting=0; pPar->lost=0; pPar->sndIn=0; pPar->sndOut=0; pPar->sndISRInfo = (struct canbus_intern_transmit *)Allocate_Memory(MAX_EVENTS*sizeof(struct canbus_intern_transmit)); if (!pPar->sndISRInfo) goto error; if(pPar->access.pOpen) ret = (*pPar->access.pOpen)(pPar->pDeviceParm); //if(pPar->access.pInit) // (*pPar->access.pInit)(pPar->pDeviceParm); } if(ret >= 0) { pPar->bOpen++; TRACE("canbus4linux_open_device -3-"); if (canbus4linux_test_device(pPar) == 0) { INFO_TRACE("Warning: no device detected"); } } TRACE("canbus4linux_open_device -> ok"); return ret; error: INFO_TRACE("out of memory while allocation buffer"); Free_Memory(pPar->sndISRInfo); pPar->sndISRInfo = NULL; pPar->sndIn = 0; pPar->sndOut = 0; return -ENOMEM; } /***************************************************************************************/ int canbus4linux_close_device(struct canbus_admin *pPar) { if(pPar->bOpen <= 0) // already closed return 0; pPar->bOpen--; if(pPar->bOpen == 0) // now ready to close ? { int ret = 0; if(pPar->access.pClose) (*pPar->access.pClose)(pPar->pDeviceParm); Free_Memory(pPar->sndISRInfo); pPar->sndISRInfo = NULL; pPar->sndIn = 0; pPar->sndOut = 0; TRACE("canbus4linux_close_device -> ok"); return ret; } return 0; } /***************************************************************************************/ int canbus4linux_init_device(struct canbus_admin *pPar) { if(pPar->bOpen && pPar->driver_registered && pPar->access.pInit) { TRACE("canbus4linux_init_device"); return (*pPar->access.pInit)(pPar->pDeviceParm); } INFO_TRACE("error in canbus4linux_init_device %p %p %d %d",pPar,pPar->access.pInit,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ int canbus4linux_test_device(struct canbus_admin *pPar) { if(pPar->bOpen && pPar->driver_registered && pPar->access.pTestDevice) { TRACE("sja1000_test_device"); return (*pPar->access.pTestDevice)(pPar->pDeviceParm); } INFO_TRACE("error in sja1000_test_device %p %p %d %d",pPar,pPar->access.pInit,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ int canbus4linux_set_baudrate(struct canbus_admin *pPar, unsigned long baudrate) { pPar->iBaudrate = baudrate; if(pPar->bOpen && pPar->driver_registered && pPar->access.pSetBaudrate) { return (*pPar->access.pSetBaudrate)(pPar->pDeviceParm,baudrate); } //INFO_TRACE("error in canbus4linux_set_baudrate %p %p %d %d",pPar,pPar->access.pSetBaudrate,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ unsigned long canbus4linux_get_baudrate(struct canbus_admin *pPar) { return pPar->iBaudrate; } /***************************************************************************************/ unsigned long canbus4linux_get_baudrate_by_constant(struct canbus_admin *pPar) { return pPar->iBaudrate; } /***************************************************************************************/ int canbus4linux_get_properties(struct canbus_admin *pPar, struct canbus_properties *props) { if(/*pPar->bOpen &&*/ pPar->driver_registered && pPar->access.pGetProperty) { props->version = 0; strcpy(props->device_name,pPar->cDeviceName); return (*pPar->access.pGetProperty)(pPar->pDeviceParm,props); } INFO_TRACE("error in canbus4linux_get_properties %p %p %d %d",pPar,pPar->access.pGetProperty,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ int canbus4linux_set_register(struct canbus_admin *pPar, int addresse, unsigned int value) { if(/*pPar->bOpen &&*/ pPar->driver_registered && pPar->access.pSetRegister) { return (*pPar->access.pSetRegister)(pPar->pDeviceParm,addresse,value); } INFO_TRACE("error in canbus4linux_set_register %p %p %d %d",pPar,pPar->access.pSetRegister,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ int canbus4linux_get_register(struct canbus_admin *pPar, int addresse, int *value) { if(/*pPar->bOpen &&*/ pPar->driver_registered && pPar->access.pGetRegister) { return (*pPar->access.pGetRegister)(pPar->pDeviceParm,addresse,value); } INFO_TRACE("error in canbus4linux_get_register %p %p %d %d",pPar,pPar->access.pGetRegister,pPar->driver_registered,pPar->bOpen); return 0; } /***************************************************************************************/ int canbus4linux_set_can_mode(struct canbus_admin *pPar, int can_2b) { pPar->bCan_2B = can_2b; if(pPar->bOpen && pPar->driver_registered && pPar->access.pSetCanMode) { int ret; ret = (*pPar->access.pSetCanMode)(pPar->pDeviceParm,can_2b); canbus4linux_init_device(pPar); return ret; } INFO_TRACE("error in canbus4linux_set_can_mode %p %p %d %d",pPar,pPar->access.pSetCanMode,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ int canbus4linux_set_baudrate_by_constant(struct canbus_admin *pPar, unsigned long constante) { pPar->iBaudrate = constante; if(pPar->bOpen && pPar->driver_registered && pPar->access.pSetBaudrateByConstant) { return (*pPar->access.pSetBaudrateByConstant)(pPar->pDeviceParm,constante); } INFO_TRACE("error in canbus4linux_set_baudrate_by_constant %p %p %d %d",pPar,pPar->access.pSetBaudrateByConstant,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ int canbus4linux_set_acceptance_filter(struct canbus_admin *pPar, struct canbus_acceptance_filter *filter) { memcpy(&pPar->acceptance_filter,filter,sizeof(struct canbus_acceptance_filter)); if(pPar->bOpen && pPar->driver_registered && pPar->access.pSetAcceptanceFilter) { return (*pPar->access.pSetAcceptanceFilter)(pPar->pDeviceParm,&pPar->acceptance_filter); } INFO_TRACE("error in canbus4linux_set_acceptance_filter %p %p %d %d",pPar,pPar->access.pSetAcceptanceFilter,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ struct canbus_acceptance_filter canbus4linux_get_acceptance_filter(struct canbus_admin *pPar) { return pPar->acceptance_filter; } /***************************************************************************************/ int canbus4linux_set_soft_acceptance_filter(struct canbus_admin *pPar, struct canbus_acceptance_filter *filter) { memcpy(&pPar->soft_acceptance_filter,filter,sizeof(struct canbus_acceptance_filter)); pPar->soft_acceptance_filter.code &= pPar->soft_acceptance_filter.mask; return 0; } /***************************************************************************************/ struct canbus_acceptance_filter canbus4linux_get_soft_acceptance_filter(struct canbus_admin *pPar) { return pPar->soft_acceptance_filter; } /***************************************************************************************/ int canbus4linux_set_command(struct canbus_admin *pPar, int command) { if(command == CANBUS_CMD_ENTER_STANDBY) { pPar->standby=1; } if(command == CANBUS_CMD_LEAVE_STANDBY) { pPar->standby=0; } if(command == CANBUS_CMD_ABORT_TRANSMISSION) { pPar->sndIn = pPar->sndOut; pPar->transmitting = 0; } if(command == CANBUS_CMD_VIRTUALIZE_ON) { pPar->virtualize = 1; return 0; } if(command == CANBUS_CMD_VIRTUALIZE_OFF) { pPar->virtualize = 0; return 0; } if(pPar->bOpen && pPar->driver_registered && pPar->access.pSetCommand) { return (*pPar->access.pSetCommand)(pPar->pDeviceParm,command); } INFO_TRACE("error in canbus4linux_set_command %p %p %d %d",pPar,pPar->access.pSetCommand,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ int canbus4linux_set_default_frame_format(struct canbus_admin *pPar, int fmt) { pPar->bFrameFmt=fmt; return 0; } /***************************************************************************************/ int canbus4linux_transmit_data(struct canbus_admin *pPar, struct canbus_transmit_data *trans, struct file *fa_file) { if(pPar->bOpen && pPar->driver_registered && pPar->access.pTransmitData && pPar->sndISRInfo) { int fmt=trans->fmt; // error check if(fmt < CANBUS_TRANS_FMT_DEFAULT) fmt = CANBUS_TRANS_FMT_DEFAULT; if(fmt > CANBUS_TRANS_FMT_EXT) fmt = CANBUS_TRANS_FMT_EXT; // format check if(!pPar->bCan_2B) // mode is set to CAN 2.0A { fmt = CANBUS_TRANS_FMT_STD; // send data always as standard frame } else { if(!fmt) { if(!pPar->bFrameFmt) fmt = CANBUS_TRANS_FMT_EXT; else fmt = pPar->bFrameFmt; } } if(pPar->transmitting) { int t; memcpy(&pPar->sndISRInfo[pPar->sndIn].data,trans,sizeof(struct canbus_transmit_data)); pPar->sndISRInfo[pPar->sndIn].data.fmt = fmt; pPar->sndISRInfo[pPar->sndIn].fa_file = fa_file; t = (1+pPar->sndIn)%MAX_EVENTS; if(t == pPar->sndOut) { if (fa_file && !(fa_file->f_flags & O_NONBLOCK) && fa_file->private_data) { struct canbus_file *cf = (struct canbus_file *)fa_file->private_data; cf->sleeping_send_wait=1; interruptible_sleep_on(&cf->send_wait); if(t == pPar->sndOut) { return -EAGAIN; } } else { return -EAGAIN; } } if (fa_file && fa_file->private_data) { struct canbus_file *cf = (struct canbus_file *)fa_file->private_data; cf->send_counter++; } pPar->sndIn = t; return 0; } pPar->transmitting = 1; memcpy(&pPar->send_data.data,trans,sizeof(struct canbus_transmit_data)); pPar->send_data.data.fmt = fmt; pPar->send_data.fa_file = fa_file; if (fa_file && fa_file->private_data) { struct canbus_file *cf = (struct canbus_file *)fa_file->private_data; cf->send_counter++; } if(pPar->standby) { canbus4linux_set_command(pPar,CANBUS_CMD_LEAVE_STANDBY); } return (*pPar->access.pTransmitData)(pPar->pDeviceParm,&pPar->send_data.data); } INFO_TRACE("error in canbus4linux_transmit_data %p %p %d %d",pPar,pPar->access.pTransmitData,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ int canbus4linux_get_event(struct canbus_admin *pPar, struct canbus_event *trans, struct canbus_file *cf) { if(pPar->bOpen && cf/*&& pPar->driver_registered && pPar->admISRInfo*/) { TRACE("canbus4linux_get_event -1-"); if(cf->admIn != cf->admOut) { TRACE("canbus4linux_get_event -2-"); memcpy(trans,&cf->admISRInfo[cf->admOut],sizeof(struct canbus_event)); cf->admOut = (1+cf->admOut)%MAX_EVENTS; return 1; } return 0; } INFO_TRACE("error in canbus4linux_get_event %p %d %d",pPar,pPar->driver_registered,pPar->bOpen); return -ENODEV; } /***************************************************************************************/ //int canbus4linux_check_received_msg(struct canbus_admin *pPar, struct canbus_event *pEvent) //{ // unsigned long tmp = (pPar->acceptance_filter.code ^ pEvent->data.identifier) | pPar->acceptance_filter.mask | 0xc0000000; // // INFO_TRACE("check %lx %lx %lx => %lx => %lx",pPar->acceptance_filter.code,pEvent->data.identifier,pPar->acceptance_filter.mask,pPar->acceptance_filter.code ^ pEvent->data.identifier,tmp); // if (tmp == 0xffffffff) // return 1; // return 0; //} /***************************************************************************************/ int canbus4linux_interrupt(void *pSpecificPar, struct canbus_admin *pPar, struct canbus_event *pEvent) { TRACE("canbus4linux_interrupt -1-"); if(pPar && pEvent && /*pPar->async_queue && */pPar->bOpen) { //struct fasync_struct *fa=pPar->async_queue; struct canbus_file *cf; int t; int max=1000; TRACE("canbus4linux_interrupt -2-"); pEvent->time = GetTime(); if(pEvent->event == CANBUS_EVENT_LEAVING_STANDBY) { pPar->standby = 0; // every event means "wake up" } for(cf = pPar->cf_first,max=1000;cf && max;cf=cf->next,max--) { memcpy(&cf->admISRInfo[cf->admIn],pEvent,sizeof(struct canbus_event)); if(pEvent->event == CANBUS_EVENT_TRANSMITTED) { // sended data are in pPar->send_data !!! memcpy(&cf->admISRInfo[cf->admIn].data,&pPar->send_data.data,sizeof(struct canbus_transmit_data)); if(cf->file == pPar->send_data.fa_file) { cf->send_counter--; } else if(pPar->virtualize) { // only the application, who sent the data get the CANBUS_EVENT_TRANSMITTED message // all other apps gets CANBUS_EVENT_RECEIVED (virtual can bus) cf->admISRInfo[cf->admIn].event = CANBUS_EVENT_RECEIVED; cf->admISRInfo[cf->admIn].lost = 0; } if(cf->sleeping_send_wait) { cf->sleeping_send_wait=0; wake_up_interruptible(&cf->send_wait); } } // Test Software acceptance filter if(cf->adm && (cf->admISRInfo[cf->admIn].event == CANBUS_EVENT_RECEIVED)) { if( !(cf->adm->soft_acceptance_filter.code == (cf->admISRInfo[cf->admIn].data.identifier & cf->adm->soft_acceptance_filter.mask))) continue; } t = (1+cf->admIn)%MAX_EVENTS; if(t == cf->admOut) { if(pEvent->event == CANBUS_EVENT_RECEIVED) pPar->lost++; } else { if(pEvent->event == CANBUS_EVENT_RECEIVED) { cf->admISRInfo[cf->admIn].lost = pPar->lost; pPar->lost = 0; } cf->admIn = t; } if(cf->sleeping_send_read) { TRACE("canbus4linux_irq -> read sleep -> wakeup"); cf->sleeping_send_read=0; wake_up_interruptible(&cf->send_read); } } // if there are any data to send, send it now and only once (because of that, this code mustn't be in the loop above !!!) if(pPar->sndIn != pPar->sndOut) { memcpy(&pPar->send_data,&pPar->sndISRInfo[pPar->sndOut],sizeof(struct canbus_intern_transmit)); pPar->sndOut = (1+pPar->sndOut)%MAX_EVENTS; if(pPar->standby) canbus4linux_set_command(pPar,CANBUS_CMD_LEAVE_STANDBY); if(pPar->access.pTransmitData) (*pPar->access.pTransmitData)(pPar->pDeviceParm,&pPar->send_data.data); } else { for(cf = pPar->cf_first,max=1000;cf && max;cf=cf->next,max--) { wake_up_interruptible(&cf->sended); } pPar->transmitting = 0; } if(pPar->async_queue) { TRACE("canbus4linux_interrupt -3-"); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) kill_fasync(&pPar->async_queue,SIGIO,POLL_IN); // 2.4.0 #else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,18) kill_fasync(pPar->async_queue,SIGIO,POLL_IN); // 2.2.18 #else kill_fasync(pPar->async_queue,SIGIO); // 2.2.16 #endif #endif } return 1; } return 0; } /***************************************************************************************/ static const char zeichen_toupper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static const char zeichen_tolower[] = "abcdefghijklmnopqrstuvwxyz"; /***************************************************************************************/ char mytoupper(char data) { int p; if ((data >= 'a') && (data <= 'z')) { p = data-'a'; data = zeichen_toupper[p]; } return data; } /***************************************************************************************/ char mytolower(char data) { int p; if ((data >= 'A') && (data <= 'Z')) { p = data-'A'; data = zeichen_tolower[p]; } return data; } /***************************************************************************************/ int myAtoi(const char *buffer) { int ret=0; int m=1,t,x=0; // searching the first digit for(t=0;t = '0') && (buffer[t] <= '9') ) { x = t; break; } } for(t=x+1;t '9') break; if(buffer[t] < '0') break; m *= 10; } for(t=x;t '9') break; if(buffer[t] < '0') break; ret = ret + (buffer[t]-'0')*m; m /= 10; } return ret; } /***************************************************************************************/ int htoi(unsigned long *x, const char *buffer) { int ret=0; int t; char z; if(!buffer[0]) return 0; // searching the first digit for(t=0;t = '0') && (z <= '9')) || ((z >= 'a') && (z <= 'f')) ) { break; } } for(;t = '0') && (z <= '9')) || ((z >= 'a') && (z <= 'f')) ) { if((z >= '0') && (z <= '9')) ret = (ret<<4) + (z-'0'); else ret = (ret<<4) + (z-'a'+10); } else break; } *x = ret; return t; } /***************************************************************************************/ int canbus4linux_read_baudrate_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int len; sprintf(page,"%lu\n",pPar->iBaudrate); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_write_baudrate_proc(struct file *file, const char *page, unsigned long count, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; unsigned long baudrate; baudrate = myAtoi(page); if(canbus4linux_open_device(pPar) >= 0) { canbus4linux_set_baudrate(pPar, baudrate); canbus4linux_close_device(pPar); } return count; } /***************************************************************************************/ int canbus4linux_read_can_mode_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int len; sprintf(page,"%d [%s]\n",pPar->bCan_2B,(pPar->bCan_2B==CANBUS_FORMAT_CAN_2_0_A)?"CAN 2.0 A":"CAN 2.0 B"); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_write_can_mode_proc(struct file *file, const char *page, unsigned long count, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int m; m = myAtoi(page); if(canbus4linux_open_device(pPar) >= 0) { canbus4linux_set_can_mode(pPar, m); canbus4linux_close_device(pPar); } return count; } /***************************************************************************************/ int canbus4linux_read_can_format_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; const char *fmt; int len; switch(pPar->bFrameFmt) { default: case CANBUS_TRANS_FMT_DEFAULT: fmt = "default (2.0 A => 11 bit, 2.0 B => 29 bit)"; break; case CANBUS_TRANS_FMT_STD: fmt = "standard (11 bit)"; break; case CANBUS_TRANS_FMT_EXT: fmt = "extended (29 bit)"; break; } sprintf(page,"%d [%s]\n",pPar->bFrameFmt,fmt); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_write_can_format_proc(struct file *file, const char *page, unsigned long count, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; pPar->bFrameFmt = myAtoi(page); return count; } /***************************************************************************************/ int canbus4linux_read_can_filter_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int len; sprintf(page,"%08lx %08lx\n",pPar->acceptance_filter.code,pPar->acceptance_filter.mask); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_write_can_filter_proc(struct file *file, const char *page, unsigned long count, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; struct canbus_acceptance_filter filter; int x; memset(&filter,0,sizeof(filter)); x = htoi(&filter.code, page); htoi(&filter.mask,&page[x]); if(canbus4linux_open_device(pPar) >= 0) { canbus4linux_set_acceptance_filter(pPar, &filter); canbus4linux_close_device(pPar); } return count; } /***************************************************************************************/ int canbus4linux_read_can_soft_filter_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int len; sprintf(page,"%08lx %08lx\n",pPar->soft_acceptance_filter.code,pPar->soft_acceptance_filter.mask); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_write_can_soft_filter_proc(struct file *file, const char *page, unsigned long count, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; struct canbus_acceptance_filter filter; int x; memset(&filter,0,sizeof(filter)); x = htoi(&filter.code, page); htoi(&filter.mask,&page[x]); if(canbus4linux_open_device(pPar) >= 0) { canbus4linux_set_soft_acceptance_filter(pPar, &filter); canbus4linux_close_device(pPar); } return count; } /***************************************************************************************/ int canbus4linux_read_register_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int len=0; int value; struct proc_registers *pProc= (struct proc_registers *)data; if(pProc) { struct canbus_admin *pPar = pProc->pAdmin; if(pPar) { if(canbus4linux_open_device(pPar) >= 0) { canbus4linux_get_register(pPar, pProc->register_nr,&value); TRACE("read register %03d : %02x",pProc->register_nr,value); canbus4linux_close_device(pPar); } else INFO_TRACE("Can't open device while reading register"); sprintf(page,"%02x\n",value); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; } else INFO_TRACE("Error pPar = NULL while read_register_proc()"); } else INFO_TRACE("Error pProc = NULL while read_register_proc()"); return len; } /***************************************************************************************/ int canbus4linux_write_register_proc(struct file *file, const char *page, unsigned long count, void *data) { unsigned long value; struct proc_registers *pProc= (struct proc_registers *)data; if(pProc) { struct canbus_admin *pPar = pProc->pAdmin; if(pPar) { if(canbus4linux_open_device(pPar) >= 0) { htoi(&value, page); canbus4linux_set_register(pPar, pProc->register_nr,(int)value); TRACE("write register %03d : %02lx",pProc->register_nr,value); canbus4linux_close_device(pPar); } else INFO_TRACE("Can't open device while writing register"); } else INFO_TRACE("Error pPar = NULL while write_register_proc()"); } else INFO_TRACE("Error pProc = NULL while write_register_proc()"); return count; } /***************************************************************************************/ int canbus4linux_read_standby_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int len; sprintf(page,"%d\n",pPar->standby); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_write_standby_proc(struct file *file, const char *page, unsigned long count, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int m = myAtoi(page); if(canbus4linux_open_device(pPar) >= 0) { if(m) canbus4linux_set_command(pPar, CANBUS_CMD_ENTER_STANDBY); else canbus4linux_set_command(pPar, CANBUS_CMD_LEAVE_STANDBY); canbus4linux_close_device(pPar); } return count; } /***************************************************************************************/ int canbus4linux_read_virtualize_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int len; sprintf(page,"%d\n",pPar->virtualize); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_write_virtualize_proc(struct file *file, const char *page, unsigned long count, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; pPar->virtualize = myAtoi(page); return count; } /***************************************************************************************/ int canbus4linux_read_lost_msg_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int len; sprintf(page,"%lu\n",pPar->lost); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_read_busload_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int len; sprintf(page,"%d\n",pPar->busload); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_transmit_from_char(const char *page, unsigned long count, struct canbus_admin *pPar, struct file *file) { struct canbus_transmit_data d; int x=0; int ret=0; unsigned long t; memset(&d,0,sizeof(d)); x += htoi(&t, &page[x]); // Can ID d.identifier = t; x += htoi(&t, &page[x]); // rtr d.rtr = (unsigned char)t; x += htoi(&t, &page[x]); // dlc d.dlc = (unsigned char)t; x += htoi(&t, &page[x]); // 8 Data Bytes d.msg[0] = (unsigned char)t; x += htoi(&t, &page[x]); d.msg[1] = (unsigned char)t; x += htoi(&t, &page[x]); d.msg[2] = (unsigned char)t; x += htoi(&t, &page[x]); d.msg[3] = (unsigned char)t; x += htoi(&t, &page[x]); d.msg[4] = (unsigned char)t; x += htoi(&t, &page[x]); d.msg[5] = (unsigned char)t; x += htoi(&t, &page[x]); d.msg[6] = (unsigned char)t; x += htoi(&t, &page[x]); d.msg[7] = (unsigned char)t; ret = canbus4linux_transmit_data(pPar, &d, file); return ret; } /***************************************************************************************/ int canbus4linux_write_transmit(struct file *file, const char *page, unsigned long count, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; if(canbus4linux_open_device(pPar) >= 0) { canbus4linux_transmit_from_char(page, count, pPar, NULL); canbus4linux_close_device(pPar); } return count; } /***************************************************************************************/ int canbus4linux_read_settings_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct canbus_admin *pPar= (struct canbus_admin *)data; int len; int p; strcpy(page,pPar->cDeviceName); for(p=0;p bOpen)?"opened":"closed"); canbus4linux_get_properties(pPar, &pPar->props); sprintf(&page[strlen(page)],"baudrates: %ld - %ld\n",pPar->props.min,pPar->props.max); sprintf(&page[strlen(page)],"baudrate mode: %s\n",(pPar->props.number_baudrates!=0)?"fix baudrates (list)":"calculating bit timing registers"); if(pPar->props.number_baudrates) { for(p=0;(p props.number_baudrates) && (p props.baudrates[p]); } } sprintf(&page[strlen(page)],"supported chipset flags: "); if(pPar->props.chipset_flags & CANBUS_CFS_CAN_2_0_A) sprintf(&page[strlen(page)],"CANBUS_CFS_CAN_2_0_A "); if(pPar->props.chipset_flags & CANBUS_CFS_CAN_2_0_B) sprintf(&page[strlen(page)],"CANBUS_CFS_CAN_2_0_B "); if(pPar->props.chipset_flags & CANBUS_CFS_EXT_FRAME) sprintf(&page[strlen(page)],"CANBUS_CFS_EXT_FRAME "); if(pPar->props.chipset_flags & CANBUS_CFS_POLLING) sprintf(&page[strlen(page)],"CANBUS_CFS_POLLING "); sprintf(&page[strlen(page)],"\n"); sprintf(&page[strlen(page)],"can mode: %s\n",(pPar->bCan_2B==0)?"2.0A":"2.0B"); for(p=0;p props.number_commands;p++) { sprintf(&page[strlen(page)],"supported command: %s\n",canbus4linux_commands[pPar->props.commands[p]]); } sprintf(&page[strlen(page)],"lowlevel access: register 0x0000...0x%04x\n",pPar->props.number_registers-1); if(canbus4linux_open_device(pPar) >= 0) { if(canbus4linux_test_device(pPar) > 0) sprintf(&page[strlen(page)],"hardware detected\n"); else sprintf(&page[strlen(page)],"hardware not detected\n"); canbus4linux_close_device(pPar); } else { sprintf(&page[strlen(page)],"hardware not detected\n"); } sprintf(&page[strlen(page)],"\n"); len = strlen(page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ int canbus4linux_read_number_drv_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { // Code aus drivers/char/rtc.c // // Calculating the number of registered drivers int len,t,number=0; for(t=0;t count) len = count; if (len < 0) len = 0; return len; } /***************************************************************************************/ void canbus4linux_proc_driver_dir(struct canbus_admin *pPar, int num, int remove) { char name[10]; struct proc_dir_entry *res; if(canbus4linux_proc_dir) { sprintf(name,"%d",num); if(!remove) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,18) pPar->proc_dir = proc_mkdir(name,canbus4linux_proc_dir); #else pPar->proc_dir = create_proc_entry(name,S_IFDIR,canbus4linux_proc_dir); #endif if(pPar->proc_dir) { if(pPar->proc_regs) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,18) pPar->proc_register_dir = proc_mkdir("register",pPar->proc_dir); #else pPar->proc_register_dir = create_proc_entry("register",S_IFDIR,pPar->proc_dir); #endif } else pPar->proc_register_dir = NULL; if(pPar->proc_register_dir) { char register_name[10]; int n; for(n=0;n props.number_registers;n++) { sprintf(register_name,"%03d",n); res = create_proc_entry(register_name,0777,pPar->proc_register_dir); if(res) { res->read_proc = canbus4linux_read_register_proc; res->write_proc = canbus4linux_write_register_proc; res->data = &pPar->proc_regs[n]; } } } res = create_proc_entry("information",0,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_settings_proc; res->data = pPar; } res = create_proc_entry("baudrate",0777,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_baudrate_proc; res->write_proc = canbus4linux_write_baudrate_proc; res->data = pPar; } res = create_proc_entry("mode",0777,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_can_mode_proc; res->write_proc = canbus4linux_write_can_mode_proc; res->data = pPar; } res = create_proc_entry("format",0777,pPar->proc_dir); // 11 bit, or 29 bit Frame format if(res) { res->read_proc = canbus4linux_read_can_format_proc; res->write_proc = canbus4linux_write_can_format_proc; res->data = pPar; } // Old name for Hardware filter, maybe this entry will be deleted in the future res = create_proc_entry("filter",0777,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_can_filter_proc; res->write_proc = canbus4linux_write_can_filter_proc; res->data = pPar; } res = create_proc_entry("hardware_filter",0777,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_can_filter_proc; res->write_proc = canbus4linux_write_can_filter_proc; res->data = pPar; } res = create_proc_entry("software_filter",0777,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_can_soft_filter_proc; res->write_proc = canbus4linux_write_can_soft_filter_proc; res->data = pPar; } res = create_proc_entry("standby",0777,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_standby_proc; res->write_proc = canbus4linux_write_standby_proc; res->data = pPar; } res = create_proc_entry("lost",0777,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_lost_msg_proc; res->data = pPar; } res = create_proc_entry("busload",0777,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_busload_proc; res->data = pPar; } res = create_proc_entry("transmit",0777,pPar->proc_dir); if(res) { res->write_proc = canbus4linux_write_transmit; res->data = pPar; } res = create_proc_entry("virtualize",0777,pPar->proc_dir); if(res) { res->read_proc = canbus4linux_read_virtualize_proc; res->write_proc = canbus4linux_write_virtualize_proc; res->data = pPar; } } } else { if(pPar->proc_dir) { TRACE("remove proc/canbus/%s/baudrate",name); remove_proc_entry("baudrate",pPar->proc_dir); TRACE("remove proc/canbus/%s/mode",name); remove_proc_entry("mode",pPar->proc_dir); TRACE("remove proc/canbus/%s/format",name); remove_proc_entry("format",pPar->proc_dir); // 11 bit, or 29 bit Frame format TRACE("remove proc/canbus/%s/filter",name); remove_proc_entry("filter",pPar->proc_dir); TRACE("remove proc/canbus/%s/hardware_filter",name); remove_proc_entry("hardware_filter",pPar->proc_dir); TRACE("remove proc/canbus/%s/software_filter",name); remove_proc_entry("software_filter",pPar->proc_dir); TRACE("remove proc/canbus/%s/standby",name); remove_proc_entry("standby",pPar->proc_dir); TRACE("remove proc/canbus/%s/lost",name); remove_proc_entry("lost",pPar->proc_dir); TRACE("remove proc/canbus/%s/busload",name); remove_proc_entry("busload",pPar->proc_dir); TRACE("remove proc/canbus/%s/transmit",name); remove_proc_entry("transmit",pPar->proc_dir); TRACE("remove proc/canbus/%s/virtualize",name); remove_proc_entry("virtualize",pPar->proc_dir); TRACE("remove proc/canbus/%s/information",name); remove_proc_entry("information",pPar->proc_dir); if(pPar->proc_register_dir) { char register_name[10]; int n; TRACE("remove proc/canbus/%s/register/xxx",name); for(n=0;n props.number_registers;n++) { sprintf(register_name,"%03d",n); remove_proc_entry(register_name,pPar->proc_register_dir); } TRACE("remove proc/canbus/%s/register (directory)",name); remove_proc_entry("register",pPar->proc_dir); pPar->proc_register_dir = 0; } TRACE("remove proc/canbus/%s (directory)",name); remove_proc_entry(name,canbus4linux_proc_dir); } pPar->proc_dir = NULL; } } } /***************************************************************************************/ int canbus4linux_register_device(char *name, int version, void *pSpecificPar, struct canbus_access *access, int prefered_min, int prefered_max) { int t; if (prefered_min < 0) prefered_min = 0; if (prefered_max < 0) prefered_max = NUM_CANBUS_DEVICES; TRACE("registering can device: %s",name); for(t=prefered_min;(t pRegisterIsr) (access->pRegisterIsr)(pSpecificPar, canbus4linux_interrupt, &canbus4linux_admin[t]); canbus4linux_admin[t].driver_registered = 1; canbus4linux_get_properties(&canbus4linux_admin[t], &canbus4linux_admin[t].props); if(canbus4linux_admin[t].props.number_registers) { int n; canbus4linux_admin[t].proc_regs = Allocate_Memory(sizeof(struct proc_registers)*canbus4linux_admin[t].props.number_registers); for(n=0;n = 0) { struct canbus_event ev; TRACE("Initializing can device -2-"); if(!canbus4linux_test_device(&canbus4linux_admin[t])) { INFO_TRACE("Warning: no device detected"); } canbus4linux_get_properties(&canbus4linux_admin[t], &canbus4linux_admin[t].props); canbus4linux_set_baudrate(&canbus4linux_admin[t], canbus4linux_admin[t].iBaudrate); canbus4linux_set_acceptance_filter(&canbus4linux_admin[t], &canbus4linux_admin[t].acceptance_filter); canbus4linux_set_can_mode(&canbus4linux_admin[t], canbus4linux_admin[t].bCan_2B); canbus4linux_set_default_frame_format(&canbus4linux_admin[t], canbus4linux_admin[t].bFrameFmt); if(canbus4linux_admin[t].standby) canbus4linux_set_command(&canbus4linux_admin[t], CANBUS_CMD_ENTER_STANDBY); ev.event = CANBUS_EVENT_DEVICE_CHANGED; canbus4linux_interrupt(canbus4linux_admin[t].pDeviceParm, &canbus4linux_admin[t], &ev); } } TRACE("canbus4linux_register_device() - finished"); return t; } } return -1; } /***************************************************************************************/ int canbus4linux_unregister_device(int can_num) { if (canbus4linux_admin[can_num].driver_registered != 0) { TRACE("unregistering can device: %s",canbus4linux_admin[can_num].cDeviceName); canbus4linux_proc_driver_dir(&canbus4linux_admin[can_num],can_num, 1); if(canbus4linux_admin[can_num].bOpen) { struct canbus_event ev; if(canbus4linux_admin[can_num].access.pClose) (*canbus4linux_admin[can_num].access.pClose)(canbus4linux_admin[can_num].pDeviceParm); ev.event = CANBUS_EVENT_DEVICE_CHANGED; canbus4linux_interrupt(canbus4linux_admin[can_num].pDeviceParm, &canbus4linux_admin[can_num], &ev); canbus4linux_admin[can_num].access.pTransmitData = 0; } if (canbus4linux_admin[can_num].access.pUnregisterIsr) (canbus4linux_admin[can_num].access.pUnregisterIsr)(canbus4linux_admin[can_num].pDeviceParm); memset(&canbus4linux_admin[can_num].access, 0,sizeof(struct canbus_access)); canbus4linux_admin[can_num].transmitting = 0; canbus4linux_admin[can_num].lost = 0; canbus4linux_admin[can_num].cDeviceName[0] = 0; canbus4linux_admin[can_num].pDeviceParm = NULL; if(canbus4linux_admin[can_num].proc_regs) Free_Memory(canbus4linux_admin[can_num].proc_regs); canbus4linux_admin[can_num].proc_regs = NULL; canbus4linux_admin[can_num].driver_registered = 0; } return 0; } /***************************************************************************************/ /***************************************************************************************/ void *Allocate_Memory(unsigned long s) { unsigned char *x; unsigned long t; x = kmalloc(s,GFP_KERNEL); if (x) { for(t=0;t adm; if(!a->cf_first) { TRACE("SetCanbusFileEntry -1-"); a->cf_first = f; } else { TRACE("SetCanbusFileEntry -2-"); n = a->cf_first; while(n->next) n = n->next; n->next = f; } f->next = NULL; } /***************************************************************************************/ void DeleteCanbusFileEntry(struct canbus_file *f) { struct canbus_file *n; struct canbus_admin *a = f->adm; if(f == a->cf_first) { TRACE("DeleteCanbusFileEntry -1-"); a->cf_first = f->next; } else { TRACE("DeleteCanbusFileEntry -2-"); n = a->cf_first; while(n->next) { if(f == n->next) { TRACE("DeleteCanbusFileEntry -3-"); n->next = n->next->next; break; } n = n->next; } } f->next = NULL; } /***************************************************************************************/ int canbus4linux_open(struct inode * inode, struct file * file) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) unsigned int minor = MINOR(inode->i_rdev); #else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,67) unsigned int minor = MINOR(inode->i_rdev.value); #else unsigned int minor = MINOR(inode->i_rdev); #endif #endif struct canbus_file *cf=NULL; if(!file) { INFO_TRACE("no file structure !!!"); return -ENODEV; } if(minor >= NUM_CANBUS_DEVICES) { INFO_TRACE("minor number exceeds internal list"); return -ENODEV; } cf = (struct canbus_file *)Allocate_Memory(sizeof(struct canbus_file)); file->private_data = cf; if(!cf) goto error; cf->adm = &canbus4linux_admin[minor]; cf->sleeping_send_wait = 0; cf->sleeping_send_read = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) init_waitqueue_head(&cf->sended); init_waitqueue_head(&cf->send_wait); init_waitqueue_head(&cf->send_read); #else cf->sended = NULL; cf->send_wait = NULL; cf->send_read = NULL; #endif cf->file = file; cf->send_counter = 0; cf->write_buffer_pos=0; cf->admIn=0; cf->admOut=0; cf->admISRInfo = (struct canbus_event *)Allocate_Memory(MAX_EVENTS*sizeof(struct canbus_event)); if (!cf->admISRInfo) goto error; SetCanbusFileEntry(cf); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,67) MOD_INC_USE_COUNT; #endif TRACE("canbus4linux_open %d",minor); return canbus4linux_open_device(&canbus4linux_admin[minor]); error: INFO_TRACE("out of memory while allocation buffer"); if(cf) { Free_Memory(cf->admISRInfo); } Free_Memory(cf); return -ENOMEM; } /***************************************************************************************/ int canbus4linux_release(struct inode * inode, struct file * file) { struct canbus_file *cf=NULL; if(file) cf = (struct canbus_file *)file->private_data; if(cf) { if (!(file->f_flags & O_NONBLOCK) && (cf->adm->sndIn != cf->adm->sndOut)) { interruptible_sleep_on(&cf->sended); } canbus4linux_close_device(cf->adm); if(file->f_flags & FASYNC) canbus4linux_fasync(-1,file,0); DeleteCanbusFileEntry(cf); Free_Memory(cf->admISRInfo); Free_Memory(cf); } file->private_data = NULL; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,67) MOD_DEC_USE_COUNT; #endif return 0; } /***************************************************************************************/ int canbus4linux_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int status=0; struct canbus_file *cf=NULL; struct canbus_acceptance_filter canbus_acceptance_filter; struct canbus_transmit_data canbus_transmit_data; struct canbus_event canbus_event; struct canbus_time canbus_time; struct canbus_properties canbus_properties; if(file) cf = (struct canbus_file *)file->private_data; if(!cf) { TRACE("no canbus_file structure"); return -ENODEV; } if(cf->adm->bOpen <= 0) { INFO_TRACE("ioctl - device not open"); return -ENODEV; } status = -EINVAL; TRACE("canbus4linux_ioctl cmd:%x %x",(int)cmd,(int)CANBUS4LINUX_WRITE_TRANSMIT_DATA); switch(cmd) { case CANBUS4LINUX_WRITE_ACCEPTANCE_FILTER: TRACE("CANBUS4LINUX_WRITE_ACCEPTANCE_FILTER"); if(verify_area(VERIFY_READ,(struct canbus_acceptance_filter *)arg,sizeof(struct canbus_acceptance_filter)) < 0) { TRACE("error in verify_area"); break; } copy_from_user(&canbus_acceptance_filter,(struct canbus_acceptance_filter *)arg,sizeof(struct canbus_acceptance_filter)); status = canbus4linux_set_acceptance_filter(cf->adm, &canbus_acceptance_filter); break; case CANBUS4LINUX_READ_ACCEPTANCE_FILTER: TRACE("CANBUS4LINUX_READ_ACCEPTANCE_FILTER"); if(verify_area(VERIFY_WRITE,(struct canbus_acceptance_filter *)arg,sizeof(struct canbus_acceptance_filter)) < 0) { TRACE("error in verify_area"); break; } canbus_acceptance_filter = canbus4linux_get_acceptance_filter(cf->adm); copy_to_user((struct canbus_acceptance_filter *)arg,&canbus_acceptance_filter,sizeof(struct canbus_acceptance_filter)); status = 0; // = ok break; case CANBUS4LINUX_SET_BAUDRATE: TRACE("CANBUS4LINUX_SET_BAUDRATE"); status = canbus4linux_set_baudrate(cf->adm, arg); break; case CANBUS4LINUX_GET_BAUDRATE: TRACE("CANBUS4LINUX_GET_BAUDRATE"); status = canbus4linux_get_baudrate(cf->adm); break; case CANBUS4LINUX_INIT: TRACE("CANBUS4LINUX_INIT"); status = canbus4linux_init_device(cf->adm); break; case CANBUS4LINUX_SET_BAUDRATE_BY_CONSTANT: TRACE("CANBUS4LINUX_SET_BAUDRATE_BY_CONSTANT"); status = canbus4linux_set_baudrate_by_constant(cf->adm, arg); break; case CANBUS4LINUX_GET_BAUDRATE_BY_CONSTANT: TRACE("CANBUS4LINUX_GET_BAUDRATE_BY_CONSTANT"); status = canbus4linux_get_baudrate_by_constant(cf->adm); break; case CANBUS4LINUX_SET_CAN_MODE: TRACE("CANBUS4LINUX_SET_CAN_MODE"); status = canbus4linux_set_can_mode(cf->adm,arg); break; case CANBUS4LINUX_SET_COMMAND: TRACE("CANBUS4LINUX_SET_COMMAND"); status = canbus4linux_set_command(cf->adm,arg); break; case CANBUS4LINUX_WRITE_TRANSMIT_DATA: TRACE("CANBUS4LINUX_WRITE_TRANSMIT_DATA"); if(verify_area(VERIFY_READ, (struct canbus_transmit_data *)arg,sizeof(struct canbus_transmit_data)) < 0) { TRACE("error in verify_area"); break; } copy_from_user(&canbus_transmit_data, (struct canbus_transmit_data *)arg,sizeof(struct canbus_transmit_data)); status = canbus4linux_transmit_data(cf->adm, &canbus_transmit_data,file); break; case CANBUS4LINUX_READ_EVENT_DATA: TRACE("CANBUS4LINUX_READ_EVENT_DATA"); if(verify_area(VERIFY_WRITE,(struct canbus_event *)arg,sizeof(struct canbus_event)) < 0) { TRACE("error in verify_area"); break; } status = canbus4linux_get_event(cf->adm,&canbus_event,cf); copy_to_user((struct canbus_event *)arg,&canbus_event,sizeof(struct canbus_event)); break; case CANBUS4LINUX_READ_TIME: TRACE("CANBUS4LINUX_READ_TIME"); if(verify_area(VERIFY_WRITE,(struct canbus_time *)arg,sizeof(struct canbus_time)) < 0) { TRACE("error in verify_area"); break; } canbus_time = GetTime(); copy_to_user((struct canbus_time *)arg,&canbus_time,sizeof(struct canbus_time)); status = 0; break; case CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT: TRACE("CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT"); status = canbus4linux_set_default_frame_format(cf->adm, arg); status = 0; break; case CANBUS4LINUX_TEST_DEVICE: TRACE("CANBUS4LINUX_TEST_DEVICE"); status = canbus4linux_test_device(cf->adm); break; case CANBUS4LINUX_READ_PROPERTIES: TRACE("CANBUS4LINUX_READ_PROPERTIES"); if(verify_area(VERIFY_WRITE,(struct canbus_properties *)arg,sizeof(struct canbus_properties)) < 0) { TRACE("error in verify_area"); break; } status = canbus4linux_get_properties(cf->adm,&canbus_properties); copy_to_user((struct canbus_properties *)arg,&canbus_properties,sizeof(struct canbus_properties)); break; case CANBUS4LINUX_WRITE_SOFT_ACCEPTANCE_FILTER: TRACE("CANBUS4LINUX_WRITE_SOFTWARE_ACCEPTANCE_FILTER"); if(verify_area(VERIFY_READ,(struct canbus_acceptance_filter *)arg,sizeof(struct canbus_acceptance_filter)) < 0) { TRACE("error in verify_area"); break; } copy_from_user(&canbus_acceptance_filter,(struct canbus_acceptance_filter *)arg,sizeof(struct canbus_acceptance_filter)); status = canbus4linux_set_soft_acceptance_filter(cf->adm, &canbus_acceptance_filter); break; case CANBUS4LINUX_READ_SOFT_ACCEPTANCE_FILTER: TRACE("CANBUS4LINUX_READ_SOFTWARE_ACCEPTANCE_FILTER"); if(verify_area(VERIFY_WRITE,(struct canbus_acceptance_filter *)arg,sizeof(struct canbus_acceptance_filter)) < 0) { TRACE("error in verify_area"); break; } canbus_acceptance_filter = canbus4linux_get_soft_acceptance_filter(cf->adm); copy_to_user((struct canbus_acceptance_filter *)arg,&canbus_acceptance_filter,sizeof(struct canbus_acceptance_filter)); status = 0; // = ok break; } return status; } /***************************************************************************************/ int canbus4linux_fasync(int fd, struct file *file, int mode) { struct canbus_file *cf=NULL; if(file) cf = (struct canbus_file *)file->private_data; if(!cf) { TRACE("no canbus_file structure"); return -ENODEV; } TRACE("canbus4linux_fasync %d %p %d",fd,file,mode); return fasync_helper(fd,file,mode,&cf->adm->async_queue); } /***************************************************************************************/ unsigned int canbus4linux_poll(struct file *file, poll_table *wait) { struct canbus_file *cf = (struct canbus_file *)file->private_data; unsigned int mask=0; poll_wait(file,&cf->send_wait,wait); poll_wait(file,&cf->send_read,wait); if (cf->admIn != cf->admOut) mask |= POLLIN | POLLRDNORM; if (cf->adm->sndIn != cf->adm->sndOut) mask |= POLLOUT | POLLWRNORM; return mask; } /***************************************************************************************/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) int canbus4linux_fsync(struct file *file, struct dentry *dt, int datasync) #else int canbus4linux_fsync(struct file *file, struct dentry *dt) #endif { struct canbus_file *cf = (struct canbus_file *)file->private_data; if (!(file->f_flags & O_NONBLOCK) && (cf->adm->sndIn != cf->adm->sndOut)) { interruptible_sleep_on(&cf->sended); } return 0; } /***************************************************************************************/ ssize_t canbus4linux_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { int x, y=-ENODEV; struct canbus_file *cf = (struct canbus_file *)file->private_data; if(!cf) return -ENODEV; if (cf->write_buffer_pos >= NUMBER_OF_WRITE_BUFFER) { cf->write_buffer_pos=0; // internal error return -ENOMEM; } for(x=0;xwrite_buffer[cf->write_buffer_pos] = buf[x]; if ((cf->write_buffer_pos > 1) && ((cf->write_buffer[cf->write_buffer_pos] == '\n') || (cf->write_buffer[cf->write_buffer_pos] == '\r')) ) { cf->write_buffer[cf->write_buffer_pos] = 0; if(canbus4linux_open_device(cf->adm) >= 0) { y = canbus4linux_transmit_from_char(cf->write_buffer, cf->write_buffer_pos, cf->adm, file); canbus4linux_close_device(cf->adm); } cf->write_buffer_pos = 0; if(y < 0) return y; y = x+1; } else { cf->write_buffer_pos++; if (cf->write_buffer_pos >= sizeof(cf->write_buffer)) { cf->write_buffer_pos = 0; INFO_TRACE("error buffer overflow / writing wrong data"); return -ENOMEM; } } } return count; } /***************************************************************************************/ ssize_t canbus4linux_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int x,status; char buffer[100]; struct canbus_file *cf = (struct canbus_file *)file->private_data; struct canbus_event ev; if(!cf || (count < 20)) return 0; buf[0] = 0; x=2; while(x) { status = canbus4linux_get_event(cf->adm,&ev,cf); if(status) break; if (!(file->f_flags & O_NONBLOCK)) { TRACE("canbus4linux_read -> sleep"); cf->sleeping_send_read=1; interruptible_sleep_on(&cf->send_read); } else return -EAGAIN; x--; } switch(ev.event) { case CANBUS_EVENT_RECEIVED: sprintf(buffer,"received\t%lu:%lu\t%08lx\t%d\t%d",ev.time.high,ev.time.low,ev.data.identifier,ev.data.rtr,ev.data.dlc); for(x=0;(x<8) && (x = KERNEL_VERSION(2,4,0) THIS_MODULE, #endif read:canbus4linux_read, // read write:canbus4linux_write, // write poll:canbus4linux_poll, // poll ioctl:canbus4linux_ioctl, // ioctl open:canbus4linux_open, // open release:canbus4linux_release, // release fsync:canbus4linux_fsync, // fsync fasync:canbus4linux_fasync, // fasync }; /***************************************************************************************/ int init_module(void) { int result; INFO_TRACE("Version %s / %s / %s",version,__DATE__,__TIME__); result = register_chrdev(major,"canbus",&canbus4linux_fops); if (result < 0) { INFO_TRACE("Can't get MAJOR Number: %d",major); return result; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,18) canbus4linux_proc_dir = proc_mkdir(CANBUS4LINUX_PROC_DIR,&proc_root); #else canbus4linux_proc_dir = create_proc_entry(CANBUS4LINUX_PROC_DIR,S_IFDIR,&proc_root); #endif if(canbus4linux_proc_dir) { struct proc_dir_entry *res; res = create_proc_entry(CANBUS4LINUX_PROC_DIR"/devices",0,0); if(res) { res->read_proc = canbus4linux_read_number_drv_proc; res->data = NULL; } } return 0; } /***************************************************************************************/ void cleanup_module(void) { int t; TRACE("cleanup_module"); for(t=0;t "); MODULE_DESCRIPTION("canbus4linux main driver");