87 |
87 |
88 #include <linux/fs.h> |
88 #include <linux/fs.h> |
89 #include <linux/sched.h> |
89 #include <linux/sched.h> |
90 #include <linux/interrupt.h> |
90 #include <linux/interrupt.h> |
91 #include <linux/pci.h> |
91 #include <linux/pci.h> |
92 #include <linux/malloc.h> |
92 #include <linux/slab.h> |
93 #include <asm/io.h> |
93 #include <asm/io.h> |
94 #include <asm/system.h> |
94 #include <asm/system.h> |
95 #include <asm/uaccess.h> |
95 #include <asm/uaccess.h> |
96 #include <linux/errno.h> |
96 #include <linux/errno.h> |
97 #include <linux/delay.h> |
97 #include <linux/delay.h> |
131 static int me8100_release(struct inode *, struct file *); |
131 static int me8100_release(struct inode *, struct file *); |
132 static int me8100_ioctl(struct inode *, struct file *, |
132 static int me8100_ioctl(struct inode *, struct file *, |
133 unsigned int , unsigned long ); |
133 unsigned int , unsigned long ); |
134 static int me8100_fasync(int, struct file *, int); |
134 static int me8100_fasync(int, struct file *, int); |
135 static void me8100_isr(int, void *, struct pt_regs *); |
135 static void me8100_isr(int, void *, struct pt_regs *); |
|
136 static ssize_t me8100_read(struct file *, char *, size_t, loff_t *); |
136 |
137 |
137 static int me8100_init_board(me8100_info_type *, struct pci_dev *); |
138 static int me8100_init_board(me8100_info_type *, struct pci_dev *); |
138 static int me8100_reset_board(me8100_info_type *); |
139 static int me8100_reset_board(me8100_info_type *); |
139 |
140 |
140 static int me8100_read_id_a(unsigned short *, me8100_info_type *); |
141 static int me8100_read_id_a(unsigned short *, me8100_info_type *); |
169 static int me8100_setup_icsr(unsigned char *, me8100_info_type *); |
170 static int me8100_setup_icsr(unsigned char *, me8100_info_type *); |
170 static int me8100_read_icsr(unsigned char *, me8100_info_type *); |
171 static int me8100_read_icsr(unsigned char *, me8100_info_type *); |
171 static int me8100_get_board_info(me8100_info_type *, me8100_info_type *); |
172 static int me8100_get_board_info(me8100_info_type *, me8100_info_type *); |
172 static int me8100_get_int_count(me8100_int_occur_type *, me8100_info_type *); |
173 static int me8100_get_int_count(me8100_int_occur_type *, me8100_info_type *); |
173 |
174 |
|
175 static inline int DEVICE(int i) { return MINOR(i) & 0x0f; } |
|
176 static inline int SUBDEVICE(int i) { return MINOR(i) >> 4; } |
|
177 |
174 |
178 |
175 /* File operations provided by the driver */ |
179 /* File operations provided by the driver */ |
176 static struct file_operations me8100_file_operations = { |
180 static struct file_operations me8100_file_operations = { |
177 #ifdef LINUX_24 |
181 #ifdef LINUX_24 |
178 THIS_MODULE, /* owner */ |
182 owner: THIS_MODULE, /* owner */ |
179 #endif |
183 #endif |
180 NULL, /* lseek() */ |
184 llseek: NULL, /* lseek() */ |
181 NULL, /* read() */ |
185 read: me8100_read, /* read() */ |
182 NULL, /* write() */ |
186 write: NULL, /* write() */ |
183 NULL, /* readdir() */ |
187 readdir: NULL, /* readdir() */ |
184 NULL, /* poll() */ |
188 poll: NULL, /* poll() */ |
185 me8100_ioctl, /* ioctl() */ |
189 ioctl: me8100_ioctl, /* ioctl() */ |
186 NULL, /* mmap() */ |
190 mmap: NULL, /* mmap() */ |
187 me8100_open, /* open() */ |
191 open: me8100_open, /* open() */ |
188 NULL, /* flush() */ |
192 flush: NULL, /* flush() */ |
189 me8100_release, /* release() */ |
193 release: me8100_release, /* release() */ |
190 NULL, /* fsync() */ |
194 fsync: NULL, /* fsync() */ |
191 me8100_fasync, /* fasync() */ |
195 fasync: me8100_fasync, /* fasync() */ |
192 NULL, /* check_media_change()*/ |
196 lock: NULL /* lock() */ |
193 NULL, /* revalidate() */ |
|
194 NULL /* lock() */ |
|
195 }; |
197 }; |
196 |
|
197 |
198 |
198 |
199 |
199 /* |
200 /* |
200 * Routine: |
201 * Routine: |
201 * init_module |
202 * init_module |
204 * This function is executed from the system, when the driver is loaded. |
205 * This function is executed from the system, when the driver is loaded. |
205 * Actions performed: |
206 * Actions performed: |
206 * - Searches for PCI hardware. |
207 * - Searches for PCI hardware. |
207 * - Initializes detected ME8100 boards with me8100_init_board(). |
208 * - Initializes detected ME8100 boards with me8100_init_board(). |
208 * - Installs the driver in the system with register_chrdev(). |
209 * - Installs the driver in the system with register_chrdev(). |
|
210 * - Installs the me8100_isr(). //.hs |
209 * |
211 * |
210 * Parameter list: |
212 * Parameter list: |
211 * Name Type Access Description |
213 * Name Type Access Description |
212 *-------------------------------------------------------------------------- |
214 *-------------------------------------------------------------------------- |
213 * |
215 * |
472 info->int_count_1 = 0; |
474 info->int_count_1 = 0; |
473 info->int_count_2 = 0; |
475 info->int_count_2 = 0; |
474 info->int1 = 0; |
476 info->int1 = 0; |
475 info->int2 = 0; |
477 info->int2 = 0; |
476 info->file_ptr = NULL; |
478 info->file_ptr = NULL; |
|
479 info->fasync_ptr = NULL; |
477 info->board_in_use = 0; |
480 info->board_in_use = 0; |
478 spin_lock_init(&info->use_lock); |
481 spin_lock_init(&info->use_lock); |
479 |
482 |
480 |
483 |
481 /*--------------------------- Reset the board -----------------------------*/ |
484 /*--------------------------- Reset the board -----------------------------*/ |
541 * |
551 * |
542 * Description: |
552 * Description: |
543 * Function, which is executed, when a userprogramm makes the syscall |
553 * Function, which is executed, when a userprogramm makes the syscall |
544 * open. |
554 * open. |
545 * Actions performed: |
555 * Actions performed: |
546 * - It installs the drivers interrupt service routine |
|
547 * me8100_isr in the system. |
|
548 * - It remarks the board as used in the global data structure. |
556 * - It remarks the board as used in the global data structure. |
549 * |
557 * |
550 * Parameter list: |
558 * Parameter list: |
551 * Name Type Access Description |
559 * Name Type Access Description |
552 *-------------------------------------------------------------------------- |
560 *-------------------------------------------------------------------------- |
563 * 01.10.04 Guard board_in_use with spin_lock, cause of race condition |
571 * 01.10.04 Guard board_in_use with spin_lock, cause of race condition |
564 * when compiling for SMP. |
572 * when compiling for SMP. |
565 */ |
573 */ |
566 static int me8100_open(struct inode *inode_ptr, struct file *file_ptr){ |
574 static int me8100_open(struct inode *inode_ptr, struct file *file_ptr){ |
567 int minor = 0; |
575 int minor = 0; |
568 int err = 0; |
576 me8100_info_type *info; |
569 |
577 |
570 PDEBUG("me8100_open() is executed\n"); |
578 PDEBUG("*** me8100_open() is executed for pid: %d\n", file_ptr->f_owner.pid); |
571 |
579 |
572 minor = MINOR(inode_ptr->i_rdev); |
580 minor = DEVICE(inode_ptr->i_rdev); |
|
581 |
|
582 PDEBUG("*** device: %d, subdevice %d\n", DEVICE(inode_ptr->i_rdev), |
|
583 SUBDEVICE(inode_ptr->i_rdev)); |
573 |
584 |
574 if(minor >= me8100_board_count){ |
585 if(minor >= me8100_board_count){ |
575 printk(KERN_ERR"ME8100:me8100_open():Board %d doesn't exist\n", minor); |
586 printk(KERN_ERR"ME8100:me8100_open():Board %d doesn't exist\n", minor); |
576 return -ENODEV; |
587 return -ENODEV; |
577 } |
588 } |
578 |
589 info = &info_vec[minor]; |
579 spin_lock(&info_vec[minor].use_lock); |
590 |
580 if(info_vec[minor].board_in_use){ |
591 spin_lock(&info->use_lock); |
581 printk(KERN_ERR"ME8100:me8100_open():Board %d already in use\n", minor); |
592 if(info->board_in_use){ |
582 spin_unlock(&info_vec[minor].use_lock); |
593 printk(KERN_ERR "WARNING: ME8100:me8100_open():Board %d already in use\n", minor); |
583 return -EBUSY; |
594 } |
584 } |
595 ++info->board_in_use; |
585 info_vec[minor].board_in_use = 1; |
596 spin_unlock(&info->use_lock); |
586 spin_unlock(&info_vec[minor].use_lock); |
597 |
587 |
598 /* info->file_ptr = file_ptr; */ /* müssen wir uns nicht hier merken! */ |
588 info_vec[minor].file_ptr = file_ptr; |
|
589 |
|
590 err = request_irq(info_vec[minor].int_line, |
|
591 me8100_isr, |
|
592 SA_INTERRUPT | SA_SHIRQ, |
|
593 ME8100_NAME, |
|
594 (void *)&info_vec[minor]); |
|
595 if(err){ |
|
596 printk(KERN_ERR"ME8100:me8100_open():Can't get interrupt line"); |
|
597 return err; |
|
598 } |
|
599 |
599 |
600 MOD_INC_USE_COUNT; |
600 MOD_INC_USE_COUNT; |
601 |
601 |
602 return 0; |
602 return 0; |
603 } |
603 } |
629 *-------------------------------------------------------------------------- |
629 *-------------------------------------------------------------------------- |
630 * Author: GG |
630 * Author: GG |
631 * Modification: |
631 * Modification: |
632 */ |
632 */ |
633 static int me8100_release(struct inode *inode_ptr, struct file *file_ptr){ |
633 static int me8100_release(struct inode *inode_ptr, struct file *file_ptr){ |
634 int minor = 0; |
634 int minor; |
635 int err = 0; |
635 int err; |
|
636 me8100_info_type *info; |
|
637 |
636 |
638 |
637 PDEBUG("me8100_release() is executed\n"); |
639 PDEBUG("me8100_release() is executed\n"); |
638 |
640 |
639 minor = MINOR(inode_ptr->i_rdev); |
641 minor = DEVICE(inode_ptr->i_rdev); |
640 |
642 info = &info_vec[minor]; |
641 err = me8100_reset_board(&info_vec[minor]); |
643 |
642 if(err){ |
644 /* resetting the board on last close */ |
643 printk(KERN_ERR"ME8100:me8100_release():Can't reset"); |
645 |
644 return err; |
646 if (--info->board_in_use == 0) { |
645 } |
647 err = me8100_reset_board(info); |
646 |
648 if(err){ |
647 free_irq(info_vec[minor].int_line, (void *) &info_vec[minor]); |
649 printk(KERN_ERR"ME8100:me8100_release():Can't reset"); |
648 |
650 return err; |
649 /* Delete the fasync structure and free memory */ |
651 } |
650 me8100_fasync(0, file_ptr, 0); |
652 } |
651 |
653 me8100_fasync(-1, file_ptr, 0); |
652 info_vec[minor].board_in_use = 0; |
|
653 |
654 |
654 MOD_DEC_USE_COUNT; |
655 MOD_DEC_USE_COUNT; |
655 PDEBUG("me8100_release() is leaved\n"); |
656 PDEBUG("me8100_release() is leaved\n"); |
656 return 0; |
657 return 0; |
657 } |
658 } |
803 *-------------------------------------------------------------------------- |
804 *-------------------------------------------------------------------------- |
804 * Author: GG |
805 * Author: GG |
805 * Modufication: |
806 * Modufication: |
806 */ |
807 */ |
807 static int me8100_fasync(int fd, struct file *file_ptr, int mode){ |
808 static int me8100_fasync(int fd, struct file *file_ptr, int mode){ |
808 int val = 0; |
809 int val; |
809 struct fasync_struct *fasync_ptr; |
810 int minor; |
810 |
811 me8100_info_type *info; |
811 fasync_ptr = file_ptr->private_data; |
812 |
|
813 minor = DEVICE(file_ptr->f_dentry->d_inode->i_rdev); |
|
814 info = &info_vec[minor]; |
812 |
815 |
813 PDEBUG("me8100_fasync() is executed\n"); |
816 PDEBUG("me8100_fasync() is executed\n"); |
814 |
817 PDEBUG("** fasync_ptr: %p\n", info->fasync_ptr); |
815 val = fasync_helper(fd, file_ptr, mode, &fasync_ptr); |
818 val = fasync_helper(fd, file_ptr, mode, &info->fasync_ptr); |
816 file_ptr->private_data = fasync_ptr; |
819 PDEBUG("** fasync_ptr: %p\n", info->fasync_ptr); |
817 return val; |
820 return val; |
818 } |
821 } |
819 |
|
820 |
822 |
821 |
823 |
822 |
824 |
823 /* |
825 /* |
824 * Routine: |
826 * Routine: |
1997 *-------------------------------------------------------------------------- |
1999 *-------------------------------------------------------------------------- |
1998 * Author: GG |
2000 * Author: GG |
1999 * Modification: |
2001 * Modification: |
2000 */ |
2002 */ |
2001 static void me8100_isr(int irq, void *dev_id, struct pt_regs *regs){ |
2003 static void me8100_isr(int irq, void *dev_id, struct pt_regs *regs){ |
2002 unsigned char icsr = 0; |
2004 unsigned char icsr; |
2003 unsigned short dummy = 0; |
2005 unsigned short dummy; |
2004 me8100_info_type *board_context; |
2006 me8100_info_type *info; |
2005 struct fasync_struct *fasync_ptr; |
|
2006 |
2007 |
2007 PDEBUG("me8100_isr() is executed\n"); |
2008 PDEBUG("me8100_isr() is executed\n"); |
2008 |
2009 |
2009 board_context = (me8100_info_type *) dev_id; |
2010 info = (me8100_info_type *) dev_id; |
2010 |
2011 |
2011 fasync_ptr = board_context->file_ptr->private_data; |
2012 if(irq != info->int_line){ |
2012 |
|
2013 if(irq != board_context->int_line){ |
|
2014 PDEBUG("me8100_isr():incorrect interrupt num: %d\n", irq); |
2013 PDEBUG("me8100_isr():incorrect interrupt num: %d\n", irq); |
2015 return; |
2014 return; |
2016 } |
2015 } |
2017 |
2016 |
2018 board_context->int1 = 0; |
2017 info->int1 = 0; |
2019 board_context->int2 = 0; |
2018 info->int2 = 0; |
2020 |
2019 |
2021 icsr = inb(board_context->plx_regbase + PLX_ICSR); |
2020 icsr = inb(info->plx_regbase + PLX_ICSR); |
2022 |
2021 |
2023 if((icsr & 0x04)&&(icsr & 0x40)&&(icsr & 0x01)){ |
2022 if((icsr & 0x04)&&(icsr & 0x40)&&(icsr & 0x01)){ |
2024 PDEBUG("me8100_isr():Int1 occured\n"); |
2023 PDEBUG("me8100_isr():Int1 occured\n"); |
2025 board_context->int1 = 1; |
2024 info->int1 = 1; |
2026 board_context->int_count_1++; |
2025 info->int_count_1++; |
2027 dummy = inw(board_context->me8100_regbase + ME8100_RES_INT_REG_A); |
2026 dummy = inw(info->me8100_regbase + ME8100_RES_INT_REG_A); |
2028 } |
2027 } |
2029 |
2028 |
2030 if((icsr & 0x20)&&(icsr & 0x40)&&(icsr & 0x08)){ |
2029 if((icsr & 0x20)&&(icsr & 0x40)&&(icsr & 0x08)){ |
2031 PDEBUG("me8100_isr():Int2 occured\n"); |
2030 PDEBUG("me8100_isr():Int2 occured\n"); |
2032 board_context->int2 = 1; |
2031 info->int2 = 1; |
2033 board_context->int_count_2++; |
2032 info->int_count_2++; |
2034 dummy = inw(board_context->me8100_regbase + ME8100_RES_INT_REG_B); |
2033 dummy = inw(info->me8100_regbase + ME8100_RES_INT_REG_B); |
2035 } |
2034 } |
2036 |
2035 |
2037 if(!(board_context->int1 || board_context->int2)){ |
2036 if(!(info->int1 || info->int2)){ |
2038 PDEBUG("me8100_isr():Not this Board\n"); |
2037 PDEBUG("me8100_isr():Not this Board\n"); |
2039 return; |
2038 return; |
2040 } |
2039 } |
2041 |
2040 |
2042 if(fasync_ptr){ |
2041 if(info->fasync_ptr){ |
2043 PDEBUG("me8100_isr():send signal to process\n"); |
2042 PDEBUG("*** me8100_isr():send signal to process %p->%d\n", |
2044 kill_fasync(&fasync_ptr, SIGIO, POLL_IN); |
2043 info->fasync_ptr, info->fasync_ptr->fa_file->f_owner.pid); |
|
2044 kill_fasync(&info->fasync_ptr, SIGIO, POLL_IN); |
2045 } |
2045 } |
2046 } |
2046 } |
2047 |
2047 |
2048 |
2048 |
2049 |
2049 |
2065 * Author: GG |
2065 * Author: GG |
2066 * Modification: |
2066 * Modification: |
2067 */ |
2067 */ |
2068 void cleanup_module(void){ |
2068 void cleanup_module(void){ |
2069 extern unsigned int major; |
2069 extern unsigned int major; |
|
2070 int minor; |
2070 int err; |
2071 int err; |
2071 |
2072 |
|
2073 |
2072 PDEBUG("cleanup_module() is executed\n"); |
2074 PDEBUG("cleanup_module() is executed\n"); |
|
2075 |
|
2076 for (minor = me8100_board_count - 1; minor > -1; --minor) { |
|
2077 free_irq(info_vec[minor].int_line, (void *) &info_vec[minor]); |
|
2078 } |
2073 |
2079 |
2074 if(major){ |
2080 if(major){ |
2075 err = unregister_chrdev(major, ME8100_NAME); |
2081 err = unregister_chrdev(major, ME8100_NAME); |
2076 if(err) |
2082 if(err) |
2077 printk(KERN_WARNING"ME8100:cleanup_module():cannot unregister major\n"); |
2083 printk(KERN_WARNING"ME8100:cleanup_module():cannot unregister major\n"); |
2078 } |
2084 } |
2079 } |
2085 } |
|
2086 |
|
2087 ssize_t me8100_read(struct file * file_ptr, char *buffer, size_t len, loff_t *offset) { |
|
2088 PDEBUG("me8100_read() called\n"); |
|
2089 return -EINVAL; |
|
2090 } |
|
2091 |
|
2092 /* |
|
2093 vim:sts=2 sw=2 aw ai sm: |
|
2094 */ |
|
2095 |