📄 vlsi_ir.c
字号:
break; case SIOCSMEDIABUSY: if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; } irda_device_set_media_busy(ndev, TRUE); break; case SIOCGRECEIVING: /* the best we can do: check whether there are any bytes in rx fifo. * The trustable window (in case some data arrives just afterwards) * may be as short as 1usec or so at 4Mbps. */ fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; irq->ifr_receiving = (fifocnt!=0) ? 1 : 0; break; default: IRDA_WARNING("%s: notsupp - cmd=%04x\n", __FUNCTION__, cmd); ret = -EOPNOTSUPP; } return ret;}/********************************************************/static irqreturn_t vlsi_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct net_device *ndev = dev_instance; vlsi_irda_dev_t *idev = ndev->priv; unsigned iobase; u8 irintr; int boguscount = 5; unsigned long flags; int handled = 0; iobase = ndev->base_addr; spin_lock_irqsave(&idev->lock,flags); do { irintr = inb(iobase+VLSI_PIO_IRINTR); mb(); outb(irintr, iobase+VLSI_PIO_IRINTR); /* acknowledge asap */ if (!(irintr&=IRINTR_INT_MASK)) /* not our INT - probably shared */ break; handled = 1; if (unlikely(!(irintr & ~IRINTR_ACTIVITY))) break; /* nothing todo if only activity */ if (irintr&IRINTR_RPKTINT) vlsi_rx_interrupt(ndev); if (irintr&IRINTR_TPKTINT) vlsi_tx_interrupt(ndev); } while (--boguscount > 0); spin_unlock_irqrestore(&idev->lock,flags); if (boguscount <= 0) IRDA_MESSAGE("%s: too much work in interrupt!\n", __FUNCTION__); return IRQ_RETVAL(handled);}/********************************************************/static int vlsi_open(struct net_device *ndev){ vlsi_irda_dev_t *idev = ndev->priv; int err = -EAGAIN; char hwname[32]; if (pci_request_regions(idev->pdev, drivername)) { IRDA_WARNING("%s: io resource busy\n", __FUNCTION__); goto errout; } ndev->base_addr = pci_resource_start(idev->pdev,0); ndev->irq = idev->pdev->irq; /* under some rare occasions the chip apparently comes up with * IRQ's pending. We better w/c pending IRQ and disable them all */ outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR); if (request_irq(ndev->irq, vlsi_interrupt, SA_SHIRQ, drivername, ndev)) { IRDA_WARNING("%s: couldn't get IRQ: %d\n", __FUNCTION__, ndev->irq); goto errout_io; } if ((err = vlsi_create_hwif(idev)) != 0) goto errout_irq; sprintf(hwname, "VLSI-FIR @ 0x%04x", (unsigned)ndev->base_addr); idev->irlap = irlap_open(ndev,&idev->qos,hwname); if (!idev->irlap) goto errout_free_ring; do_gettimeofday(&idev->last_rx); /* first mtt may start from now on */ idev->new_baud = 9600; /* start with IrPHY using 9600(SIR) mode */ if ((err = vlsi_start_hw(idev)) != 0) goto errout_close_irlap; netif_start_queue(ndev); IRDA_MESSAGE("%s: device %s operational\n", __FUNCTION__, ndev->name); return 0;errout_close_irlap: irlap_close(idev->irlap);errout_free_ring: vlsi_destroy_hwif(idev);errout_irq: free_irq(ndev->irq,ndev);errout_io: pci_release_regions(idev->pdev);errout: return err;}static int vlsi_close(struct net_device *ndev){ vlsi_irda_dev_t *idev = ndev->priv; netif_stop_queue(ndev); if (idev->irlap) irlap_close(idev->irlap); idev->irlap = NULL; vlsi_stop_hw(idev); vlsi_destroy_hwif(idev); free_irq(ndev->irq,ndev); pci_release_regions(idev->pdev); IRDA_MESSAGE("%s: device %s stopped\n", __FUNCTION__, ndev->name); return 0;}static int vlsi_irda_init(struct net_device *ndev){ vlsi_irda_dev_t *idev = ndev->priv; struct pci_dev *pdev = idev->pdev; SET_MODULE_OWNER(ndev); ndev->irq = pdev->irq; ndev->base_addr = pci_resource_start(pdev,0); /* PCI busmastering * see include file for details why we need these 2 masks, in this order! */ if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW) || pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) { IRDA_ERROR("%s: aborting due to PCI BM-DMA address limitations\n", __FUNCTION__); return -1; } irda_init_max_qos_capabilies(&idev->qos); /* the VLSI82C147 does not support 576000! */ idev->qos.baud_rate.bits = IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 | IR_1152000 | (IR_4000000 << 8); idev->qos.min_turn_time.bits = qos_mtt_bits; irda_qos_bits_to_value(&idev->qos); /* currently no public media definitions for IrDA */ ndev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA; ndev->if_port = IF_PORT_UNKNOWN; ndev->open = vlsi_open; ndev->stop = vlsi_close; ndev->get_stats = vlsi_get_stats; ndev->hard_start_xmit = vlsi_hard_start_xmit; ndev->do_ioctl = vlsi_ioctl; ndev->tx_timeout = vlsi_tx_timeout; ndev->watchdog_timeo = 500*HZ/1000; /* max. allowed turn time for IrLAP */ SET_NETDEV_DEV(ndev, &pdev->dev); return 0;} /**************************************************************/static int __devinitvlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id){ struct net_device *ndev; vlsi_irda_dev_t *idev; if (pci_enable_device(pdev)) goto out; else pdev->current_state = 0; /* hw must be running now */ IRDA_MESSAGE("%s: IrDA PCI controller %s detected\n", drivername, PCIDEV_NAME(pdev)); if ( !pci_resource_start(pdev,0) || !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) { IRDA_ERROR("%s: bar 0 invalid", __FUNCTION__); goto out_disable; } ndev = alloc_irdadev(sizeof(*idev)); if (ndev==NULL) { IRDA_ERROR("%s: Unable to allocate device memory.\n", __FUNCTION__); goto out_disable; } idev = ndev->priv; spin_lock_init(&idev->lock); init_MUTEX(&idev->sem); down(&idev->sem); idev->pdev = pdev; if (vlsi_irda_init(ndev) < 0) goto out_freedev; if (register_netdev(ndev) < 0) { IRDA_ERROR("%s: register_netdev failed\n", __FUNCTION__); goto out_freedev; } if (vlsi_proc_root != NULL) { struct proc_dir_entry *ent; ent = create_proc_entry(ndev->name, S_IFREG|S_IRUGO, vlsi_proc_root); if (!ent) { IRDA_WARNING("%s: failed to create proc entry\n", __FUNCTION__); } else { ent->data = ndev; ent->proc_fops = VLSI_PROC_FOPS; ent->size = 0; } idev->proc_entry = ent; } IRDA_MESSAGE("%s: registered device %s\n", drivername, ndev->name); pci_set_drvdata(pdev, ndev); up(&idev->sem); return 0;out_freedev: up(&idev->sem); free_netdev(ndev);out_disable: pci_disable_device(pdev);out: pci_set_drvdata(pdev, NULL); return -ENODEV;}static void __devexit vlsi_irda_remove(struct pci_dev *pdev){ struct net_device *ndev = pci_get_drvdata(pdev); vlsi_irda_dev_t *idev; if (!ndev) { IRDA_ERROR("%s: lost netdevice?\n", drivername); return; } unregister_netdev(ndev); idev = ndev->priv; down(&idev->sem); if (idev->proc_entry) { remove_proc_entry(ndev->name, vlsi_proc_root); idev->proc_entry = NULL; } up(&idev->sem); free_netdev(ndev); pci_set_drvdata(pdev, NULL); IRDA_MESSAGE("%s: %s removed\n", drivername, PCIDEV_NAME(pdev));}#ifdef CONFIG_PM/* The Controller doesn't provide PCI PM capabilities as defined by PCI specs. * Some of the Linux PCI-PM code however depends on this, for example in * pci_set_power_state(). So we have to take care to perform the required * operations on our own (particularly reflecting the pdev->current_state) * otherwise we might get cheated by pci-pm. */static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state){ struct net_device *ndev = pci_get_drvdata(pdev); vlsi_irda_dev_t *idev; if (!ndev) { IRDA_ERROR("%s - %s: no netdevice \n", __FUNCTION__, PCIDEV_NAME(pdev)); return 0; } idev = ndev->priv; down(&idev->sem); if (pdev->current_state != 0) { /* already suspended */ if (state.event > pdev->current_state) { /* simply go deeper */ pci_set_power_state(pdev, pci_choose_state(pdev, state)); pdev->current_state = state.event; } else IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state.event); up(&idev->sem); return 0; } if (netif_running(ndev)) { netif_device_detach(ndev); vlsi_stop_hw(idev); pci_save_state(pdev); if (!idev->new_baud) /* remember speed settings to restore on resume */ idev->new_baud = idev->baud; } pci_set_power_state(pdev, pci_choose_state(pdev, state)); pdev->current_state = state.event; idev->resume_ok = 1; up(&idev->sem); return 0;}static int vlsi_irda_resume(struct pci_dev *pdev){ struct net_device *ndev = pci_get_drvdata(pdev); vlsi_irda_dev_t *idev; if (!ndev) { IRDA_ERROR("%s - %s: no netdevice \n", __FUNCTION__, PCIDEV_NAME(pdev)); return 0; } idev = ndev->priv; down(&idev->sem); if (pdev->current_state == 0) { up(&idev->sem); IRDA_WARNING("%s - %s: already resumed\n", __FUNCTION__, PCIDEV_NAME(pdev)); return 0; } pci_set_power_state(pdev, PCI_D0); pdev->current_state = PM_EVENT_ON; if (!idev->resume_ok) { /* should be obsolete now - but used to happen due to: * - pci layer initially setting pdev->current_state = 4 (unknown) * - pci layer did not walk the save_state-tree (might be APM problem) * so we could not refuse to suspend from undefined state * - vlsi_irda_suspend detected invalid state and refused to save * configuration for resume - but was too late to stop suspending * - vlsi_irda_resume got screwed when trying to resume from garbage * * now we explicitly set pdev->current_state = 0 after enabling the * device and independently resume_ok should catch any garbage config. */ IRDA_WARNING("%s - hm, nothing to resume?\n", __FUNCTION__); up(&idev->sem); return 0; } if (netif_running(ndev)) { pci_restore_state(pdev); vlsi_start_hw(idev); netif_device_attach(ndev); } idev->resume_ok = 0; up(&idev->sem); return 0;}#endif /* CONFIG_PM *//*********************************************************/static struct pci_driver vlsi_irda_driver = { .name = drivername, .id_table = vlsi_irda_table, .probe = vlsi_irda_probe, .remove = __devexit_p(vlsi_irda_remove),#ifdef CONFIG_PM .suspend = vlsi_irda_suspend, .resume = vlsi_irda_resume,#endif};#define PROC_DIR ("driver/" DRIVER_NAME)static int __init vlsi_mod_init(void){ int i, ret; if (clksrc < 0 || clksrc > 3) { IRDA_ERROR("%s: invalid clksrc=%d\n", drivername, clksrc); return -1; } for (i = 0; i < 2; i++) { switch(ringsize[i]) { case 4: case 8: case 16: case 32: case 64: break; default: IRDA_WARNING("%s: invalid %s ringsize %d, using default=8", drivername, (i)?"rx":"tx", ringsize[i]); ringsize[i] = 8; break; } } sirpulse = !!sirpulse; /* proc_mkdir returns NULL if !CONFIG_PROC_FS. * Failure to create the procfs entry is handled like running * without procfs - it's not required for the driver to work. */ vlsi_proc_root = proc_mkdir(PROC_DIR, NULL); if (vlsi_proc_root) { /* protect registered procdir against module removal. * Because we are in the module init path there's no race * window after create_proc_entry (and no barrier needed). */ vlsi_proc_root->owner = THIS_MODULE; } ret = pci_module_init(&vlsi_irda_driver); if (ret && vlsi_proc_root) remove_proc_entry(PROC_DIR, NULL); return ret;}static void __exit vlsi_mod_exit(void){ pci_unregister_driver(&vlsi_irda_driver); if (vlsi_proc_root) remove_proc_entry(PROC_DIR, NULL);}module_init(vlsi_mod_init);module_exit(vlsi_mod_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -