⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtl_3c905cx_drv.c

📁 最新rtlinux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
static int rtl_3COM905C_open (struct rtl_file *filp){  rtl_3COM905C_release (filp);      if(rt_3c905c_opened == 0x00){    if((rt_3c905c_dev = rtl_3COM905C_init_device())!=NULL){      sem_init(&rt_3c905x_sem, 0, 0);            rtl_3COM905C_start_up_device(rt_3c905c_dev);      rt_3c905c_opened = 0x01;      return COM3_905C_MAJOR;    }else{      rtl_printf("ERROR: Couldn't initialize device 3Com905C-X\n");      return -1;    }  }else{    rtl_printf("Device 3Com905C-X is already opened\n");    return -1;  }}/***************************************************************************************//* This function is used to initialise the pci and the buffering subsystem.            *//***************************************************************************************/struct pci_dev *rtl_3COM905C_init_device(void){  struct pci_dev *dev;  /* First of all, we must get a pointer to the pci_dev structure */  if((dev = rt_pci_find_device(COM3_VENDOR_ID, COM3_DEVICE_ID, NULL))== NULL)    return NULL;  rt_3c905x_policy.initialize_rx_buffer(&rt_3c905x_rx_buffer);  /* Let's enable the device */  if (rt_pci_enable_device(dev)){    rtl_printf("PCI ERROR: Can't enable device 3Com905C-X\n");    return NULL;  }  return dev;}/***************************************************************************************//* This function is called when the driver module is inserted. It registers the device *//* , letting other modules to use it by means of the calls read, write, close, open    *//* and ioctl.                                                                          *//***************************************************************************************/int init_module(void){  printk("\n\n\nRT-Linux driver for the Ethernet Card 3Com905c-x being loaded\n\n\n");  if (rtl_register_rtldev (COM3_905C_MAJOR, COM3_905C_NAME, &rtl_3COM905C_fops)) {    printk ("RTLinux /dev/%s: unable to get RTLinux major %d\n", COM3_905C_NAME, COM3_905C_MAJOR);    return -EIO;  }else{    printk("Registered device 3Com905C-X: /dev/%s major number %d\n",COM3_905C_NAME, COM3_905C_MAJOR);    rt_3c905c_registered = 0x01;    return 0;  }}/***************************************************************************************//* This function is called when removing the driver module. It makes sure that there   *//* are no pending executions of the interrupt handler. It releases the ethernet card   *//* and frees all resources. The driver is unregistered.                                *//***************************************************************************************/void cleanup_module(void){  int inside = 1;  rtl_irqstate_t state;  if((rt_3c905c_opened == 0x01) || rt_3c905c_inside_the_interrupt_handler){    rt_3c905c_trying_to_close = 1;    /* Since inside the interrupt handler there's a call to the scheduler, there may  */    /* be an execution of the interrupt handler that hasn't been completely executed. */    /* The card cannot be released in that case, so we must be sure that there is no  */    /* interrupt handler execution pending. Otherwise, that may crash the system.     */    while(inside){      rtl_no_interrupts(state);                  if(rt_3c905c_inside_the_interrupt_handler){	rtl_restore_interrupts(state);	usleep(10);      }else{	rtl_hard_disable_irq(rt_3c905c_vp.pdev->irq);        	rtl_restore_interrupts(state);	inside = 0;      }    }      rtl_3COM905C_issue_and_wait(UpStall);    rtl_3COM905C_issue_and_wait(DownStall);  }  if(rt_3c905c_registered == 0x01){    printk("Unregistering device /dev/%s\n",COM3_905C_NAME);    rtl_unregister_rtldev(COM3_905C_MAJOR,COM3_905C_NAME);  }  printk("\n\n\nRT-Linux driver for the Ethernet Card 3Com905c-x being removed\n\n\n");}/***************************************************************************************//* This is the interrupt handler. It is executed when the ethernet card raises an      *//* interrupt and interrupts are enabled. In the initialisation phase we've forced the  *//* card to only generate the UpComplete interrupt, that is, when a full incoming       *//* packet has been processed.                                                          *//***************************************************************************************/unsigned int boomerang_interrupt(unsigned int irq , struct pt_regs *regs){  long ioaddr = rt_3c905c_vp.ioaddr;  int status = inw(ioaddr + EL3_STATUS);  int work_done = max_interrupt_work;  struct pci_dev *dev = rt_3c905c_dev;  rt_3c905c_inside_the_interrupt_handler = 1;  rt_3c905c_interrupted++;  if(rt_3c905c_writting & rt_3c905c_interrupted)    rtl_printf("I've been interrupted %d times\n",rt_3c905c_interrupted);  if (status & UpComplete) {    rt_3c905c_vp.rx_packets++;        rtl_3COM905C_issue_and_wait(UpStall);    while(rt_3c905c_vp.rx_ring[rt_3c905c_vp.cur_rx % RX_RING_SIZE].status & 0x00008000){      boomerang_rx(dev);      outw(AckIntr | UpComplete, ioaddr + EL3_CMD);      if (--work_done < 0)	break;    }    outw(UpUnstall, ioaddr + EL3_CMD);  }    if (status & DownComplete){    rtl_printf("Se acaba de enviar el paquete\n");    outw(AckIntr | DownComplete, ioaddr + EL3_CMD);  }    /* Check for all uncommon interrupts at once. */  if (status & (HostError | RxEarly | StatsFull | IntReq)){    rtl_printf("VORTEX_ERROR\n");    vortex_error(dev, status);  }    /* Acknowledge the IRQ. */  outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);  if (rt_3c905c_vp.cb_fn_base){	    writel(0x8000, rt_3c905c_vp.cb_fn_base + 4);  }    /* We must be sure that we're out of the interrupt handler before cleanup_modules */  /* is executed. If cleanup_modules is being executed, we don't have to enable the */  /* irq. If enabled, then the system could crash.                                  */  if(!rt_3c905c_trying_to_close)    rtl_hard_enable_irq(rt_3c905c_vp.pdev->irq);      rt_3c905c_interrupted--;  return (rt_3c905c_inside_the_interrupt_handler = 0);}/***************************************************************************************//* This is the function called when an incoming packet has succesfuly arrived, so we   *//* have to copy it into internal buffers.                                              *//***************************************************************************************/static int boomerang_rx(struct pci_dev *dev){  int entry = rt_3c905c_vp.cur_rx % RX_RING_SIZE;  int rx_status;  int rx_work_limit = rt_3c905c_vp.dirty_rx + RX_RING_SIZE - rt_3c905c_vp.cur_rx;  int i,j;  unsigned char *buffer;  int temp = rt_3c905c_vp.rx_ring[entry].status & 0x1fff;  unsigned char mine = 0x01, multicast_packet= 0x01, arp_request_for_me = 0x01 ;  buffer =rt_3c905c_vp.rx_skbuff[entry];  /* A NIC receives all the packets in the LAN so we will receive an interrupt for each one of those. */  /* As we only want those packets sent to us we must filter them. So, we will only receive packets   */  /* directly sent us (i.e. destination address is ours) and those ARP frames which ask for our MAC.  */  /* An ARP improvement consist on receive all ARP request packets in the LAN, so, at least, we could */  /* know the pair IP and MAC address of those computers performing the request. As most of the       */  /* frames in a LAN are ARP request frames the overhead produced by receiving all of them would be   */  /* considerable, so we won't bother with this improvement.                                          */  //Is this frame for us??  for(i=0; i<6; i++){    if(buffer[i] == rt_3c905c_vp.dev_addr[i])      continue;    else{      mine = 0x00;      break;    }  }  if(mine == 0x01) goto accept_frame;  // Is an ARP frame???  if((buffer[12]==0x08) && (buffer[13]==0x06)){    // It asks for my IP??    for(j=0; j<rt_3c905c_n_filters; j++){      for(i=0; i<4;i++){	if(buffer[38+i]==rt_3c905c_ip_addr[j][i])	  continue;	else{	  arp_request_for_me = 0x00;   	  break;	}      }    }  }else    arp_request_for_me = 0x00;     // Is it a multicast frame??  for(i=0; i<6; i++){    if(buffer[i] == 0xff)      continue;    else{      multicast_packet = 0x00;      break;    }  }   accept_frame:  if((mine == 0x01) || ((multicast_packet==0x01) && (arp_request_for_me==0x01))){    rt_3c905c_vp.rx_frames_for_us++;    if(rt_3c905x_policy.add_frame_to_buffer((void *) &rt_3c905x_rx_buffer,buffer,temp)== 0){      sem_post(&rt_3c905x_sem);      rtl_schedule();     }  }  while ((rx_status = le32_to_cpu(rt_3c905c_vp.rx_ring[entry].status)) & RxDComplete){    if (--rx_work_limit < 0)      break;    if (!(rx_status & RxDError))  /* Error, update stats. */      rt_3c905c_vp.stats.rx_packets++;  }  entry = (++rt_3c905c_vp.cur_rx) % RX_RING_SIZE;  /* Refill the Rx ring buffers. */  for (; rt_3c905c_vp.cur_rx - rt_3c905c_vp.dirty_rx > 0; rt_3c905c_vp.dirty_rx++) {    entry = rt_3c905c_vp.dirty_rx % RX_RING_SIZE;    rt_3c905c_vp.rx_ring[entry].status = 0;	/* Clear complete bit. */  }  return 0;}/***************************************************************************************//* This function does internal initialisations of the card. It writes into internal    *//* registers and checks the card capabilities.                                         *//***************************************************************************************/int rtl_3COM905C_start_up_device(struct pci_dev *dev){  struct vortex_chip_info * const vci = &vortex_info;  unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */  char *print_name;  int retval;  long ioaddr;  int i,step;  print_name = dev ? dev->slot_name : "3c59x";  ioaddr = rt_pci_resource_start(dev, 0);  rt_3c905c_vp.drv_flags = vci->drv_flags;  rt_3c905c_vp.has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0;  rt_3c905c_vp.io_size = vci->io_size;  rt_3c905c_vp.card_idx = 0;  rt_3c905c_vp.ioaddr = ioaddr;  rt_3c905c_vp.media_override = 7;  rt_3c905c_vp.mtu = mtu;  print_name = dev ? dev->slot_name : "3c59x";  /* PCI-only startup logic */  if (dev) {    if (request_region(ioaddr, vci->io_size, print_name) != NULL){      rt_3c905c_vp.must_free_region = 1;     }    /* enable bus-mastering if necessary */		    if (vci->flags & PCI_USES_MASTER)      pci_set_master (dev);    rt_3c905c_vp.pdev = dev;    /* Makes sure rings are at least 16 byte aligned. */    rt_3c905c_vp.rx_ring = pci_alloc_consistent(dev, sizeof(struct boom_rx_desc) * RX_RING_SIZE, &rt_3c905c_vp.rx_ring_dma);    rt_3c905c_vp.tx_ring = pci_alloc_consistent(dev, sizeof(struct boom_tx_desc) * TX_RING_SIZE, &rt_3c905c_vp.tx_ring_dma);    retval = -ENOMEM;    if ((rt_3c905c_vp.rx_ring == 0) || (rt_3c905c_vp.tx_ring == 0))      goto free_region;            EL3WINDOW(0);    {      int base;      if (vci->drv_flags & EEPROM_8BIT)	base = 0x230;      else if (vci->drv_flags & EEPROM_OFFSET)	base = EEPROM_Read + 0x30;      else	base = EEPROM_Read;      for (i = 0; i < 0x40; i++) {	int timer;		/* This means that we want to read EepromCommand Register and disable writting */	/* Issuing ReadRegister & WriteDisable                                         */	outw(base + i, ioaddr + Wn0EepromCmd);	for (timer = 10; timer >= 0; timer--) {	  /* The read data is available through the EepromData register 162us after  */	  /* the ReadRegister command has been issued                                */	  rtl_delay(162000);	  /* Bit 15th (eepromBusy) of EepromCommand register is a read-only bit asserted   */	  /* during the execution of EEProm commands. Further commans should not be issued */	  /* to the EepromCommand register, nor should data be read from the EepromData    */	  /* register while this bit is true                                               */	  if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)	    break;	}	/* Save the contents of the 3C90xC NIC's EEPROM     */ 	eeprom[i] = inw(ioaddr + Wn0EepromData);      }    }//EL3WINDOW(0) configuration finished    /* EEPROM can be checksummed in order to assure that reading was OK */    for (i = 0; i < 0x18; i++)      checksum ^= eeprom[i];    checksum = (checksum ^ (checksum >> 8)) & 0xff;    if (checksum != 0x00) {		/* Grrr, needless incompatible change 3Com. */      while (i < 0x21)	checksum ^= eeprom[i++];      checksum = (checksum ^ (checksum >> 8)) & 0xff;    }    if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO))      printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);        /* Save HW address into dev_addr (MAC address in format 00:04:75:bd:ea:e7) */    for (i = 0; i < 3; i++)      ((u16 *)rt_3c905c_vp.dev_addr)[i] = htons(eeprom[i + 10]);        /* This writes into the StationAddress register the NIC's HW address in order */    /* to define the individual destination address that the NIC responds to when */    /* receiving packets                                                          */    EL3WINDOW(2);    for (i = 0; i < 6; i++)      outb(rt_3c905c_vp.dev_addr[i], ioaddr + i);    EL3WINDOW(4);    step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1;    if (dev && vci->drv_flags & HAS_CB_FNS) {      unsigned long fn_st_addr;			/* Cardbus function status space */      unsigned short n;            fn_st_addr = pci_resource_start (dev, 2);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -