sirroom
驱动大牛
驱动大牛
  • 注册日期2001-07-30
  • 最后登录2018-05-29
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望11点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1377回复:3

请教高手,本程序如何在kernel2.4下运行?可在2.2下运行

楼主#
更多 发布于:2001-12-24 17:47
/**********************************************************

 * Module Name: ql5232.c
 * Description: kernel driver for Linux
 * Notes: none
 * Author: sirroom
 * Date: 2001-6-27 13:37
 * Reference:
 ***********************************************************/

/**********************************************************

  Modification history:
  
   =====================
   Date:
   By:
   Reason:
  
   =====================
   Date:
   By:
   Reason:
  
  

   =====================
   Date:
   By:
   Reason:

 *********************************************************/

#ifndef __KERNEL__
#define __KERNEL__
#endif

#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
const char kernel_version[] = UTS_RELEASE;

#include  <linux/pci.h>
#include  <linux/types.h>
#include  <linux/kernel.h>
#include  <linux/sched.h>    
#include  <linux/mm.h>      
#include  <linux/fs.h>
#include  <linux/time.h>
#include  <linux/ioctl.h>
#include  <linux/errno.h>
#include  <asm/io.h>
#include  <asm/uaccess.h>
#include  <asm/param.h>
#include  <asm/current.h>
#include  <asm/ptrace.h>
#include  <asm/system.h>
#include  <asm/segment.h>

/*****************
加上你自己的.h吧
#include   \"xxx.h\"
#include   \"xxx.h\"
#include   \"xxx.h\"
******************/

///////////////////////////////////////////////////////////
//// GLOBAL(S)

////--------------------------------------------------------
//// global variables
static unsigned int chips = 0;
static int major_devnum = 0;
static CHIP_INFO chip_info[MAX_CHIP];
static int init_flag = 0;

////   interrupt variables
static  unsigned int    ReadComplete;
static  unsigned int    WriteComplete;
static  unsigned int    StartRead;
static  unsigned int    StartWrite;
static  unsigned char   InterruptLine;
static struct   wait_queue     * wait_intr = NULL;

////   ioremap variables
static unsigned int base_address[MAX_CHIP] = {0};
static unsigned int space_length[MAX_CHIP] = {0};
static unsigned int *remap_addr[MAX_CHIP]= {NULL};

//// dma transfer variables
static unsigned int     pmem_for_chip_inputdata;
static unsigned int     pmem_for_chip_outputdata;
static char             * vmem_for_usr_output;
static char             * vmem_for_usr_input;


static ssize_t kf_read(
struct file *sp_file,
char *buff,
size_t count,
loff_t *offvalue);

static ssize_t kf_write(
struct file *sp_file,
const char *buff,
size_t count,
loff_t *offvalue);

static int kf_open(
struct inode *inode,
struct file *filp);

static void kf_release(
struct inode *inode,
struct file *filp);

static int kf_ioctl(
struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned int arg);

////--------------------------------------------------------
//// export symbols (unregister_chrdev)
struct file_operations file_ops = {
NULL,
(ssize_t(*)())kf_read,
(ssize_t(*)())kf_write,
NULL,
NULL,
(int(*)())kf_ioctl,
NULL,
(int(*)())kf_open,
NULL,
(int(*)())kf_release,
NULL,
NULL,
NULL,
NULL,
NULL};


////////////////////////////////////////////////////////////
//// FUNCTION(S)

////--------------------------------------------------------
//// chip base functions
//// calculate address
static inline void address_reg(unsigned int chip_id)
{
unsigned int *base = 0;
//++ remap physical address to virtual address !!!
//   function   \"ioremap\" extern in /asm/io.h
 base = (unsigned int *)ioremap(base_address[chip_id],
   space_length[chip_id]);
    
// save address maped for release
remap_addr[chip_id] = base;


  //100h
 chip_info[chip_id].addr.dma_length=
  base+QL_DMA_COUNT_REG/sizeof(unsigned int);
  //104h
 chip_info[chip_id].addr.dma_write_address=
  base+QL_DMA_WRITE_ADDRESS_REG/sizeof(unsigned int);

  //108h
 chip_info[chip_id].addr.dma_read_address=
  base+QL_DMA_READ_ADDRESS_REG/sizeof(unsigned int);

  //10ch
 chip_info[chip_id].addr.dma_control_status_reg=
  base+QL_DMA_CONTROL_STATUS_REG/sizeof(unsigned int);

  //18ch
 chip_info[chip_id].addr.int_control_status_reg=
     base+QL_INT_CONTROL_STATUS_REG/sizeof(unsigned int);

 //800h
 chip_info[chip_id].addr.microcode=
  base+QL_CODE_ADDRESS/sizeof(unsigned int);
}

//1. reset QLogic chip
static inline int reset_chip(unsigned int chip_id)
{
        *chip_info[chip_id].addr.int_control_status_reg=QLOGIC_RESET;
        return 0;
}


//2. load micro code to 800h
static inline void load_code(
unsigned int chip_id,
unsigned int *p_microcode)
{
copy_from_user(
chip_info[chip_id].addr.microcode,
p_microcode,
1152);
}

//3.Send DMA read and write parameter
static inline void QL_SEND_DMA_PARA(unsigned int chip_id,
unsigned short ReadLength,
unsigned short WriteLength,
unsigned int  ReadAddress,
unsigned int  WriteAddress)
{
         //据说有什么自动左移,偶先来个右移
     unsigned short *p1,*p2;
unsigned int ReadAddress_new,WriteAddress_new;
ReadAddress_new=ReadAddress>>2;
WriteAddress_new=WriteAddress>>2;

p1=&ReadLength;
p2=&WriteLength;
//send DMA read Length
memcpy(chip_info[chip_id].addr.dma_length,
p1-1,
4);
//send DMA write Length
memcpy(chip_info[chip_id].addr.dma_length,
p2,
sizeof(unsigned short));

//send DMA read address

memcpy(chip_info[chip_id].addr.dma_read_address,
&ReadAddress_new,
sizeof(unsigned int));

//send DMA write address
memcpy(chip_info[chip_id].addr.dma_write_address,
&WriteAddress_new,
sizeof(unsigned int));
}

//4. write c1000100 to 10ch,start DMA transfer
static inline void start_dma_transfer(unsigned int chip_id)
{
//unsigned int    cmd_status;
unsigned int instruction;
struct pci_dev *p_dev = NULL;
WriteComplete = 0;
ReadComplete = 0;
StartWrite = 1;
StartRead = 1;

p_dev = pci_find_device(
QL_5232_VENDORID,
QL_5232_DEVICEID,
p_dev);
if(p_dev == NULL){
return;
}

//config master
pci_write_config_word(p_dev,
0x4,
0x6);
pci_write_config_dword(
p_dev,
0x08,
0x0);
pci_write_config_dword(
p_dev,
0x0c,
0x4000);

instruction = QL_start_dma;//0xc1000100
memcpy(
chip_info[chip_id].addr.dma_control_status_reg,
&instruction,
sizeof(unsigned int));

}


//5. test 0,8,9,24,25 bit in 10ch.All bit is 0 stands for DMA transfer completed
static inline int wait_done(unsigned int chip_id)
{

unsigned int counter = 0;

//printk(\"enter wait_done\\n\");
//10ch 0,8,9,24,25 is zero
while(counter < MAX_LOOP){

         if(!(test_bit(0,
         chip_info[chip_id].addr.dma_control_status_reg))
         &&(!test_bit(8,
         chip_info[chip_id].addr.dma_control_status_reg))
         &&(!test_bit(9,
         chip_info[chip_id].addr.dma_control_status_reg) )
         &&(!test_bit(24,
         chip_info[chip_id].addr.dma_control_status_reg))
         &&(!test_bit(25,
         chip_info[chip_id].addr.dma_control_status_reg)))
         {      
         return 0;
}

         counter ++;
}

printk(\"Wait_done time out!\\n\");
printk(\"chip_info[chip_id].addr.dma_control_status_reg is 0x%x\\n\",
*chip_info[chip_id].addr.dma_control_status_reg);
printk(\"leave wait_done\\n\");
return -1;

}
////-------------------------------------------------------------------------
////Enable interrupt
static inline void EnableQLogicInterrupt(unsigned int chip_id)
{
unsigned int    ICSR;
memcpy(
&ICSR,
chip_info[chip_id].addr.int_control_status_reg,
4);
        ICSR=ICSR|ENABLE_DMA_WRITE_INT|ENABLE_QLOGIC_INT;
memcpy(
chip_info[chip_id].addr.int_control_status_reg,
                &ICSR,
                4);
}
////-------------------------------------------------------------------------
////Disable interrupt
static inline void DisableQLogicInterrupt(unsigned int chip_id)
{
memset(chip_info[chip_id].addr.int_control_status_reg,
0,
4);
}
                                

////----------------------------------------------------------------------
//// I/O control specified functions

static inline void ioctl_initial(INIT_INFO *arg)
{

int index, pass;
unsigned int ret;

if(init_flag == 1){

ret = SJW17_SUCCESS;
copy_to_user(arg->status, &ret, sizeof(unsigned int));

ret = chips;
copy_to_user(arg->chips, &ret, sizeof(unsigned int));
return;

}

pass = 0;

// try to initial all chips found
for(index=0; index<chips; index++){

// reset the specified chip
if(reset_chip(index) != 0){
printk(\"v2_drv: reset chip %d    [FAIL]\\n\", index);
continue;
}
//load micro code to instruction memory of the specified chip
load_code(index, arg->p_microcode);

// set ready flag of the specified chip
chip_info[index].ready_flag = 1;

pass = 1;

}

// no chip can work !!!
if(pass == 0){
ret = SJW17_FAIL_CHIP_ALLFAIL;
copy_to_user(arg->status, &ret, sizeof(unsigned int));
}
else{
ret = SJW17_SUCCESS;
copy_to_user(arg->status, &ret, sizeof(unsigned int));
init_flag = 1;
}

ret = chips;
copy_to_user(arg->chips, &ret, sizeof(unsigned int));

}

static inline void ioctl_reset(unsigned int chip_id)
{
// reset the specified chip
if(reset_chip(chip_id) != 0){
printk(\"v2_drv: reset chip %X    [FAIL]\\n\", chip_id);
return;
}
}



static inline int ioctl_activity(
unsigned int chip_id,
ACTION_INFO *arg)
{

unsigned int ret,interrupt_flags;
// check if the specified chip is ready
if(chip_info[chip_id].ready_flag != 1){
printk(\"v2_drv: no ready %X      [FAIL]\\n\", chip_id);
ret = SJW17_FAIL_CHIP_NOREADY;
copy_to_user(arg->status, &ret, sizeof(unsigned int));
return -1;
}
DisableQLogicInterrupt(chip_id);
/*
printk(\"After Disable interrupt,int_reg is 0x%8x\\n\",
*chip_info[chip_id].addr.int_control_status_reg);
*/      
//++ step 1
if(arg->InputLength > MAX_CACHE_LENGTH){
printk(\"<1>error: SJW17_FAIL_CMD_INVALID_INPUTLENGTH\\n\");
return -1;
}

// Check required data length
if(arg->OutputLength > MAX_CACHE_LENGTH){
printk(\"<1>error:SJW17_FAIL_CMD_INVALID_OUTPUTLENGTH\\n\");
return -1;
}

copy_from_user(vmem_for_usr_input,
arg->pRbuf,
(arg->InputLength*4));

QL_SEND_DMA_PARA(chip_id,
arg->InputLength,
arg->OutputLength,
pmem_for_chip_inputdata,
pmem_for_chip_outputdata);

start_dma_transfer(chip_id);
EnableQLogicInterrupt(chip_id);
/*
   printk(\"After Enable Interrupt,int_reg is 0x%8x\\n\",
*chip_info[chip_id].addr.int_control_status_reg);
*/
save_flags(interrupt_flags);
cli();

if( !WriteComplete ){
interruptible_sleep_on_timeout(&wait_intr,2*HZ);        }
        
restore_flags(interrupt_flags);
        if( WriteComplete ){
DisableQLogicInterrupt(chip_id);
copy_to_user(
               arg->pWbuf,
               vmem_for_usr_output,
               arg->OutputLength*4);
ret = SJW17_SUCCESS;
       copy_to_user(arg->status, &ret, sizeof(unsigned int));
}
       else
/*calculate again*/
{
printk(\"v2_kernel:time out!!!\\n\");
return -1;
}

return 0;

// wait the specified chip idle
/*
if(wait_done(chip_id) == -1){

printk(\"v2_drv: time out %X    [FAIL]\\n\", chip_id);

ret = SJW17_FAIL_CHIP_TIMEOUT;
copy_to_user(arg->status, &ret, sizeof(unsigned int));

return -1;

}

//printk(\"copy output data to upper layer\\n\");

copy_to_user(
arg->pWbuf,
vmem_for_usr_output,
arg->OutputLength*4);

ret = SJW17_SUCCESS;
copy_to_user(arg->status, &ret, sizeof(unsigned int));
*/
//return 0;

}


static void v2_handler(
//unsigned int chip_id,
int qlogicx ,
void * dev_id,
struct pt_regs * pqlogicx)
//unsigned int chip_id)
{
unsigned int    interrupt_flags;
unsigned int    InterruptStatus;
unsigned int chip_id=0;
//unsigned int      ICSR;

//printk(\"enter v2_handler\\n\");

save_flags(interrupt_flags);
cli();

/* Read Interrupt Registers*/
InterruptStatus=*chip_info[chip_id].addr.int_control_status_reg;

/* If QLOGIC_ASSERTED_INT is set, it\'s QLOGIC\'s interrupt */
if((InterruptStatus & QLOGIC_ASSERTED_INT) != 0){
//Class or Type Error
if((InterruptStatus &CLASS_ERROR_INT) != 0){}
//READ_TRANSFER_COMPLETE_INTERUPPT HANDLE
if((InterruptStatus & READ_TC_INT) != 0){
   InterruptStatus=
InterruptStatus|QLOGIC_ASSERTED_INT|READ_TC_INT;
   *chip_info[chip_id].addr.int_control_status_reg=
InterruptStatus;

   if( StartRead ){
  ReadComplete    = 1;
StartRead       = 0;
   }
}
//WRITE_TRANSFER_COMPLETE_INTERUPPT HANDLE
         if( ( InterruptStatus & WRITE_TC_INT ) != 0){
   InterruptStatus=
             InterruptStatus|QLOGIC_ASSERTED_INT|WRITE_TC_INT;
   *chip_info[chip_id].addr.int_control_status_reg=
InterruptStatus;

   if( StartWrite )
   {
WriteComplete   = 1;                        StartWrite      = 0;                        //Wakeup process
  wake_up_interruptible( &wait_intr );
                    }
   DisableQLogicInterrupt(chip_id);
}
}
restore_flags(interrupt_flags);
//printk(\"leave v2_handler\\n\");
}
                                      
////----------------------------------------------------------------------
//// interface functions

int init_module(void)
{
//unsigned int my_print;
int index, result;
struct pci_dev *p_dev = NULL;
int mask,interRet;

      
//++ 1: initial globals
mask = 0;
chips = 0;
major_devnum = 0;
memset(base_address, 0, sizeof(unsigned int) * MAX_CHIP);
memset(chip_info, 0, sizeof(CHIP_INFO) * MAX_CHIP);

//++ 2: search for v2-800 and get base memory address
        if(!pci_present()){
printk(\"v2_drv: find PCI bus    [FAIL]\\n\");
return -ENODEV;
  }


        //printk(\"base valus is 0x\\n\",
for(index=0; index<MAX_CHIP; index++){

p_dev = pci_find_device(
QL_5232_VENDORID,
QL_5232_DEVICEID,
p_dev);

if(p_dev == NULL){
break;
}

//chips ++;
pci_read_config_byte(
p_dev,
PCI_INTERRUPT_LINE,
&InterruptLine);
pci_read_config_dword(
p_dev,
PCI_BASE_ADDRESS_0,
&base_address[index]);

pci_write_config_dword(
p_dev,
PCI_BASE_ADDRESS_0,
~0);

pci_read_config_dword(
p_dev,
PCI_BASE_ADDRESS_0,
&mask);

pci_write_config_dword(
p_dev,
PCI_BASE_ADDRESS_0,
base_address[index]);

space_length[index] = (~mask + 1);

pci_write_config_word(p_dev,
PCI_COMMAND,
//QL_config_master);
0x162);
//register interrupt handler
interRet=request_irq(
InterruptLine,
     v2_handler,
SA_INTERRUPT|SA_SHIRQ,
\"v2-800\",
NULL);
printk(\"chip_id is %d\\n\",chips);
chips ++;
        }

if(chips == 0){
printk(\"v2_drv: find v2-800       [FAIL]\\n\");
return -ENODEV;
}

  //printk(\"v2_drv: find v2 800 * %X   [ OK ]\\n\", chips);

//++  calcualte address for 6500(s)
for(index=0; index<chips; index++){
address_reg(index);
}
     
        // Allocate 1 dma page
     if((pmem_for_chip_inputdata = __get_dma_pages(GFP_KERNEL,0))==0){
printk(\"__get_dma_pages() fail \\n\");
return -EFAULT;
   }

     if((pmem_for_chip_outputdata = __get_dma_pages(GFP_KERNEL,0))==0){                      
            printk(\"__get_dma_pages() fail \\n\");
   return -EFAULT;
     }
//conver between virtual address and physical address
     vmem_for_usr_input = (char *)phys_to_virt(pmem_for_chip_inputdata);
     vmem_for_usr_output = (char *)(phys_to_virt(pmem_for_chip_outputdata));
     pmem_for_chip_inputdata = virt_to_phys(vmem_for_usr_input);
     pmem_for_chip_outputdata = virt_to_phys(vmem_for_usr_output);
        
        //printk(\"pmem_for_chip_inputdata is 0x%x\\n\",pmem_for_chip_inputdata);
        //printk(\"pmem_for_chip_outputdata is 0x%x\\n\",pmem_for_chip_outputdata);
//++  register character device (ask for a dynamic major)
result = register_chrdev(
major_devnum,
DRIVER_NAME,
&file_ops);

if(result < 0){
printk(\"v2_drv: register driver [FAIL]\\n\");
return result;
}
if( major_devnum == 0 ){
major_devnum = result;
}

  printk(\"v2_drv: module insert   [ OK ]\\n\");
return 0;

}

void cleanup_module(void)
{
int index;

//free mem allocate in init_module
  free_pages( (unsigned int )pmem_for_chip_inputdata,  0 );
       free_pages( (unsigned int )pmem_for_chip_outputdata, 0 );
//++ unregister character device

for(index=0; index<chips; index++){
iounmap(remap_addr[index]);
free_irq(InterruptLine, NULL );
//vfree(remap_addr[index]);
}

unregister_chrdev(major_devnum, DRIVER_NAME);

  printk(\"v2_drv: module clean    [ OK ]\\n\");

}

static ssize_t kf_read(
struct file *sp_file,
char *buff,
size_t count,
loff_t *offvalue)
{


// printk(\"v2_drv: module read     [ OK ]\\n\");
return 0;
}

static ssize_t kf_write(
struct file *sp_file,
const char *buff,
size_t count,
loff_t *offvalue)
{

// printk(\"v2_drv: module write    [ OK ]\\n\");
return 0;

}

static int kf_open(
struct inode *inode,
struct file *filp)
{

// printk(\"v2_drv: module open     [ OK ]\\n\");
return 0;

}

static void kf_release(
struct inode *inode,
struct file *filp)
{

// printk(\"v2_drv: module release  [ OK ]\\n\");

}

static int kf_ioctl(
struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned int arg)
{

int err = 0;
unsigned int dev_minor = MAX_CHIP + 1;

//++ extract the type and number bitfields, and don\'t decode
if(_IOC_TYPE(cmd) != IOCC_MAGIC_){
printk(\"v2_drv: control code    [FAIL]\\n\");
return -EINVAL;
}

if(_IOC_NR(cmd) > IOCC_MAXNR_){
printk(\"v2_drv: control code    [FAIL]\\n\");
return -EINVAL;
}

//++ verify memory address

err = verify_area(
VERIFY_READ,
(void *)arg,
sizeof(unsigned int) * 3);

if(err != 0){
printk(\"v2_drv: verify area     [FAIL]\\n\");
return err;
}

//++ decode minor device number (chip id)
dev_minor = MINOR(inode->i_rdev);

if((dev_minor < 0)||(dev_minor > chips - 1)){
printk(\"v2_drv: chip id : %X     [FAIL]\\n\", dev_minor);
return -EINVAL;
}
 
// printk(\"v2_drv: chip id : %d     [ OK ]\\n\", dev_minor);

//++ decode control code
switch(cmd){

case IOCC_RESERVED:
// printk(\"v2_drv: IOCC_RESERVED   [ OK ]\\n\");
break;

case IOCC_INITIAL:
ioctl_initial((INIT_INFO *)arg);
// printk(\"v2_drv: IOCC_INITIAL    [ OK ]\\n\");
break;

case IOCC_RESET:
ioctl_reset(dev_minor);
// printk(\"v2_drv: IOCC_RESET      [ OK ]\\n\");
break;

case IOCC_ACTIVITY:
ioctl_activity(dev_minor,
(ACTION_INFO *)arg);
break;

case IOCC_REINITIAL:
// ioctl_reinitial(dev_minor);
break;
case IOCC_DEBUGONLY:
// printk(\"v2_drv: IOCC_DEBUGONLY  [ OK ]\\n\");
// ioctl_debugonly(dev_minor);
break;

default:
printk(\"v2_drv: control code    [FAIL]\\n\");
return -EINVAL;

}

return 0;

}

111
sirroom
驱动大牛
驱动大牛
  • 注册日期2001-07-30
  • 最后登录2018-05-29
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望11点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2001-12-24 17:49
ft.格式都变了哦
111
shownxu
驱动小牛
驱动小牛
  • 注册日期2002-02-05
  • 最后登录2008-04-25
  • 粉丝0
  • 关注0
  • 积分70分
  • 威望9点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-02-05 14:39
当然不可以, 有很多的东西要改
sirroom
驱动大牛
驱动大牛
  • 注册日期2001-07-30
  • 最后登录2018-05-29
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望11点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2002-03-28 21:26
说一下三。
111
游客

返回顶部