📄 main.c
字号:
/** main.c * * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de * Version 1.0 04 Feb 2003 */#ifndef __KERNEL__# define __KERNEL__#endif#ifndef MODULE# define MODULE#endif#define EXPORT_SYMTAB#include <linux/module.h>#include <linux/proc_fs.h>#include "../include/candrv.h"#include "../include/hms30c7202_can.h"#include "../include/c_can.h"//#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,8)MODULE_LICENSE("GPL");//#endif#define EXPORT_SYMTAB/* Module parameters, some must be supplied at module loading time */int major = CAN_MAJOR;MODULE_PARM(major,"i");int extended[ MAX_HW_CHIPS ] = { 0, 0 };MODULE_PARM(extended,"1-2i");int baudrate[ MAX_HW_CHIPS ] = { 125, 125 };MODULE_PARM(baudrate,"1-2i");char *hw[ MAX_HW_CHIPS ]={ NULL,NULL };MODULE_PARM(hw, "1-2s");int irq[ MAX_HW_CHIPS ]={ 0x12, 0x13 };MODULE_PARM(irq, "1-2i");unsigned long io[ MAX_HW_CHIPS ] = { 0x8002f000, 0x80030000 };MODULE_PARM(io, "1-2l");char time_triggered[ MAX_HW_CHIPS ] = { 0, 0 };MODULE_PARM(time_triggered, "1-2b");unsigned long time_trig_msec[ MAX_HW_CHIPS ] = { 10, 10 };MODULE_PARM(time_trig_msec, "1-2l");/* Global structure, used to hold information about the installed hardware. */struct canhardware_t gcanhardware;struct canhardware_t *pghw = &gcanhardware;#define EXPORT_SYMTAB/* * Pointers to dynamically allocated memory are maintained in a linked list * to ease memory deallocation. */struct mem_addr *pgmem_head = NULL;struct file_operations can_fops={ owner: THIS_MODULE, read: can_read, write: can_write, poll: can_poll, ioctl: can_ioctl, open: can_open, release: can_close,};EXPORT_SYMBOL( can_fops );////////////////////////////////////////////////////////////////////////////////* * add_mem_to_list * * Adds a pointer to allocated memory area to the linked list. */int add_mem_to_list( void *paddress ){ struct mem_addr *pmem_new;#ifdef DEBUG_MEM DEBUGMSG("add_mem_to_list %p, gmem_head=%p", paddress, gmem_head );#endif pmem_new = ( struct mem_addr * )kmalloc( sizeof( struct mem_addr ), GFP_KERNEL ); if ( pmem_new == NULL ) { CANMSG("Memory list error."); return -ENOMEM; } pmem_new->next = pgmem_head; pmem_new->address = paddress; pgmem_head = pmem_new; return 0;}////////////////////////////////////////////////////////////////////////////////* del_mem_from_list * * Removes pointer from linked list and releases memory area. */int del_mem_from_list( void *paddress ){ struct mem_addr *pmem_search = NULL; struct mem_addr *pmem_delete = NULL;#ifdef DEBUG_MEM DEBUGMSG("del_mem_from_list %p, gmem_head=%p", paddress, gmem_head );#endif pmem_search = pgmem_head; if ( pgmem_head->address == paddress ) { kfree( pgmem_head->address ); pgmem_head = pgmem_head->next; kfree( pmem_search ); } else { while (pmem_search->next->address != paddress ) { pmem_search = pmem_search->next; } kfree( pmem_search->next->address ); pmem_delete = pmem_search->next; pmem_search->next = pmem_search->next->next; kfree( pmem_delete ); } return 0;}////////////////////////////////////////////////////////////////////////////////* * del_mem_list * * Removes all pointers from the list and clears the whole allocated memory. */int del_mem_list( void ){ struct mem_addr *mem_old;#ifdef DEBUG_MEM DEBUGMSG("del_mem_list, gmem_head=%p", gmem_head);#endif while ( pgmem_head->next != NULL ) { mem_old = pgmem_head; kfree( mem_old->address ); pgmem_head = mem_old->next; kfree( mem_old ); } return 0;}////////////////////////////////////////////////////////////////////////////////* * init_module * * Called through the insmod command. * Initializes the driver corresponding to the insmod parameters. */int init_module( void ){ /* Parse command line data; cards, io, irq's */ if ( parse_args( pghw )) { return -EINVAL; } list_hw( pghw ); /* Register the character device */ if ( register_chrdev( major, DEVICE_NAME, &can_fops )) { CANMSG("Error registering driver."); return -ENODEV; } // proc_register( &proc_root, &pcimod_proc_entry ); CANMSG("CAN driver successfully installed."); return 0;/* error: ; del_mem_list(); unregister_chrdev( major, DEVICE_NAME ); return -ENODEV;*/}////////////////////////////////////////////////////////////////////////////////* * cleanup_module * * Called by rmmod. */void cleanup_module( void ){ // proc_unregister( &proc_root, pcimod_proc_entry.low_ino ); if ( del_mem_list() ) { CANMSG("Error deallocating memory"); } if ( unregister_chrdev( major, DEVICE_NAME )) { CANMSG("Error unregistering CAN driver." ); } CANMSG("CAN driver removed from the system." ); return;}////////////////////////////////////////////////////////////////////////////////* * parse_args * * Helper for init_module. Parses the insmod arguments and creates the * structures the driver works with. */int parse_args( struct canhardware_t *pghw ){ u16 cnt_hw = 0; /* Counter for chips ( hardware ) */ u16 cnt_irq = 0; /* counter for irq's */ u16 cnt_io = 0; /* Counter for io addresses */ u16 cnt_minor = 0; /* Counter for device id's */ if ( NULL == pghw ) { return -EINVAL; } if ( ( hw[ 0 ] == NULL )) { CANMSG("You must supply your type of hardware, interrupt numbers and io address.\n"); CANMSG("Example: # insmod can.o hw=hms30c7202_can irq=0x12 io=0x8002f000"); return -ENODEV; } /* Parse resources for all chips the user want us to work with */ while ( ( hw[ cnt_hw ] != NULL ) && ( cnt_hw < MAX_HW_CHIPS )) { /* Another chip */ pghw->cnt_tot_chips++; /* Allocate storage for the chip */ pghw->pchip[ cnt_hw ] = (struct chip_t *)kmalloc( sizeof(struct chip_t), GFP_KERNEL ); if ( pghw->pchip[ cnt_hw ] == NULL ) { return -ENOMEM; } else { if ( add_mem_to_list( pghw->pchip[ cnt_hw ] )) return -ENOMEM; } /* Save baudrate */ pghw->pchip[ cnt_hw ]->baudrate = baudrate[ cnt_hw ]; /* Save time triggered mode settings */ pghw->pchip[ cnt_hw ]->time_triggered = time_triggered[ cnt_hw ]; pghw->pchip[ cnt_hw ]->time_trig_nanosec = 1000000 * (u64) time_trig_msec[ cnt_hw ]; /* Save message mode */ switch ( extended[ cnt_hw ] ) { case 1: pghw->pchip[ cnt_hw ]->init_msg_mode = 1; /* extended */ break; //case 2: // pghw->pchip[ cnt_hw ]->init_msg_mode = 2; /* standard + extended */ // break; default: pghw->pchip[ cnt_hw ]->init_msg_mode = 0; /* standard ( default ) */ break; } if ( ( hw[ 0 ] != NULL ) && !strcmp( hw[ 0 ], "hms30c7202_can" )) { /**************************************************************** * * * * HMS30C7202 C-CAN device * * * * * 1 io address and 1 irq is needed ***************************************************************/ DEBUGMSG("Hardware: %s\n", hw[0] ); if ( -1 == io[ cnt_io ] ) { CANMSG("hms30c7202_can: Missing needed io base address for chip"); CANMSG("Example: # insmod can.o hw=hms30c7202_can irq=0x12 io=0x8002f000"); return -EINVAL; } if ( -1 == irq[ cnt_irq ] ) { CANMSG("hms30c7202_can: Missing needed irq for chip"); CANMSG("Example: # insmod can.o hw=hms30c7202_can irq=0x12 io=0x8002f000"); return -EINVAL; } /* Initialize the device structures */ if ( hms30c7202_init_hw_data( pghw->pchip[ cnt_hw ], cnt_hw, cnt_minor, (u32)io[ cnt_io ], (u8)irq[ cnt_irq ] )) { return -EINVAL; } cnt_io++; /* Another io used */ cnt_irq++; /* Another irq used */ cnt_minor += 32; /* Another device */ } else { CANMSG( "Sorry, hardware \"%s\" is currently not supported.", hw[ cnt_hw ] ); return -EINVAL; } cnt_hw++; /* next chip */ } /* while hw[] */ return 0;}////////////////////////////////////////////////////////////////////////////////* * list_hw * * list_hw is used when debugging is on to show the hardware layout */int list_hw( struct canhardware_t *pghw ){ int i,j; CANMSG("Debug list of hardware resources" ); CANMSG("--------------------------------" ); CANMSG("Number of chips : %d", pghw->cnt_tot_chips); for (i=0; i<pghw->cnt_tot_chips;i++) { CANMSG("--------------------------------"); CANMSG("+Chip %d",i+1); if (pghw->pchip[i]->ntype == CAN_CHIPTYPE_C_CAN) CANMSG("+Chiptype C-CAN"); else CANMSG("+Chiptype undefined"); CANMSG("+IRQ %d",pghw->pchip[i]->irq); CANMSG("+Time trig mode %d",pghw->pchip[i]->time_triggered); CANMSG("+Time trig cycle time %ld ms", (long)(pghw->pchip[i]->time_trig_nanosec / 1000000) ); CANMSG("+IO Base 0x%.8lx",(unsigned long)pghw->pchip[i]->base_addr); CANMSG("+Virtual IO Base 0x%.8lx",(unsigned long)pghw->pchip[i]->vbase_addr); CANMSG("+Number of message objects : %d", pghw->pchip[i]->obj_cnt); for (j=0;j<pghw->pchip[i]->obj_cnt;j++) { CANMSG("++Message Object %d -> Minor %d",j+1, pghw->pchip[i]->pmsgobj[j]->minor); } CANMSG("--------------------------------\n"); } return 0;}////////////////////////////////////////////////////////////////////////////////* * can_poll * * Poll function through which the user can check if nonblocking read or write * access is possible. */unsigned int can_poll( struct file *filp, poll_table *wait ){ struct msgobj_t *pmsgobj; unsigned int mask = 0; int space; if ( NULL == ( pmsgobj = filp->private_data ) ) { CANMSG("Device is not correctly configured."); CANMSG("Please reload the driver."); return -1; } poll_wait( filp, &pmsgobj->fifo->readq, wait ); poll_wait( filp, &pmsgobj->fifo->writeq, wait ); if ( pmsgobj->fifo->rxrp != pmsgobj->fifo->rxwp ) mask |= POLLIN | POLLRDNORM; /* Readable */ space = ((int)pmsgobj->fifo->txwp < (int)pmsgobj->fifo->txrp ) ? ((int)pmsgobj->fifo->txrp - (int)pmsgobj->fifo->txwp ) : ((int)pmsgobj->fifo->txrp - (int)pmsgobj->fifo->txwp + (int)pmsgobj->fifo->txsize); if ( 0 != space ) mask |= POLLOUT | POLLWRNORM; /* Writable */ return mask;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -