📄 sir_dev.c
字号:
/* Check problems */ if(spin_is_locked(&dev->tx_lock)) { IRDA_DEBUG(3, "%s(), write not completed\n", __FUNCTION__); } /* serialize with write completion */ spin_lock_irqsave(&dev->tx_lock, flags); /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ dev->tx_buff.len = async_wrap_skb(skb, dev->tx_buff.data, dev->tx_buff.truesize); /* transmission will start now - disable receive. * if we are just in the middle of an incoming frame, * treat it as collision. probably it's a good idea to * reset the rx_buf OUTSIDE_FRAME in this case too? */ atomic_set(&dev->enable_rx, 0); if (unlikely(sirdev_is_receiving(dev))) dev->stats.collisions++; actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len); if (likely(actual > 0)) { dev->tx_skb = skb; ndev->trans_start = jiffies; dev->tx_buff.data += actual; dev->tx_buff.len -= actual; } else if (unlikely(actual < 0)) { /* could be dropped later when we have tx_timeout to recover */ ERROR("%s: drv->do_write failed (%d)\n", __FUNCTION__, actual); dev_kfree_skb_any(skb); dev->stats.tx_errors++; dev->stats.tx_dropped++; netif_wake_queue(ndev); } spin_unlock_irqrestore(&dev->tx_lock, flags); return 0;}/* called from network layer with rtnl hold */static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd){ struct if_irda_req *irq = (struct if_irda_req *) rq; struct sir_dev *dev = ndev->priv; int ret = 0; ASSERT(dev != NULL, return -1;); IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, ndev->name, cmd); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else ret = sirdev_schedule_speed(dev, irq->ifr_baudrate); /* cannot sleep here for completion * we are called from network layer with rtnl hold */ break; case SIOCSDONGLE: /* Set dongle */ if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else ret = sirdev_schedule_dongle_open(dev, irq->ifr_dongle); /* cannot sleep here for completion * we are called from network layer with rtnl hold */ break; case SIOCSMEDIABUSY: /* Set media busy */ if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else irda_device_set_media_busy(dev->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = sirdev_is_receiving(dev); break; case SIOCSDTRRTS: if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else ret = sirdev_schedule_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); /* cannot sleep here for completion * we are called from network layer with rtnl hold */ break; case SIOCSMODE:#if 0 if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else ret = sirdev_schedule_mode(dev, irq->ifr_mode); /* cannot sleep here for completion * we are called from network layer with rtnl hold */ break;#endif default: ret = -EOPNOTSUPP; } return ret;}/* ----------------------------------------------------------------------------- */#define SIRBUF_ALLOCSIZE 4269 /* worst case size of a wrapped IrLAP frame */static int sirdev_alloc_buffers(struct sir_dev *dev){ dev->tx_buff.truesize = SIRBUF_ALLOCSIZE; dev->rx_buff.truesize = IRDA_SKB_MAX_MTU; /* Bootstrap ZeroCopy Rx */ dev->rx_buff.skb = __dev_alloc_skb(dev->rx_buff.truesize, GFP_KERNEL); if (dev->rx_buff.skb == NULL) return -ENOMEM; skb_reserve(dev->rx_buff.skb, 1); dev->rx_buff.head = dev->rx_buff.skb->data; dev->tx_buff.head = kmalloc(dev->tx_buff.truesize, GFP_KERNEL); if (dev->tx_buff.head == NULL) { kfree_skb(dev->rx_buff.skb); dev->rx_buff.skb = NULL; dev->rx_buff.head = NULL; return -ENOMEM; } dev->tx_buff.data = dev->tx_buff.head; dev->rx_buff.data = dev->rx_buff.head; dev->tx_buff.len = 0; dev->rx_buff.len = 0; dev->rx_buff.in_frame = FALSE; dev->rx_buff.state = OUTSIDE_FRAME; return 0;};static void sirdev_free_buffers(struct sir_dev *dev){ if (dev->rx_buff.skb) kfree_skb(dev->rx_buff.skb); if (dev->tx_buff.head) kfree(dev->tx_buff.head); dev->rx_buff.head = dev->tx_buff.head = NULL; dev->rx_buff.skb = NULL;}static int sirdev_open(struct net_device *ndev){ struct sir_dev *dev = ndev->priv; const struct sir_driver *drv = dev->drv; if (!drv) return -ENODEV; /* increase the reference count of the driver module before doing serious stuff */ if (!try_module_get(drv->owner)) return -ESTALE; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); if (sirdev_alloc_buffers(dev)) goto errout_dec; if (!dev->drv->start_dev || dev->drv->start_dev(dev)) goto errout_free; sirdev_enable_rx(dev); dev->raw_tx = 0; netif_start_queue(ndev); dev->irlap = irlap_open(ndev, &dev->qos, dev->hwname); if (!dev->irlap) goto errout_stop; netif_wake_queue(ndev); IRDA_DEBUG(2, "%s - done, speed = %d\n", __FUNCTION__, dev->speed); return 0;errout_stop: atomic_set(&dev->enable_rx, 0); if (dev->drv->stop_dev) dev->drv->stop_dev(dev);errout_free: sirdev_free_buffers(dev);errout_dec: module_put(drv->owner); return -EAGAIN;}static int sirdev_close(struct net_device *ndev){ struct sir_dev *dev = ndev->priv; const struct sir_driver *drv;// IRDA_DEBUG(0, "%s\n", __FUNCTION__); netif_stop_queue(ndev); down(&dev->fsm.sem); /* block on pending config completion */ atomic_set(&dev->enable_rx, 0); if (unlikely(!dev->irlap)) goto out; irlap_close(dev->irlap); dev->irlap = NULL; drv = dev->drv; if (unlikely(!drv || !dev->priv)) goto out; if (drv->stop_dev) drv->stop_dev(dev); sirdev_free_buffers(dev); module_put(drv->owner);out: dev->speed = 0; up(&dev->fsm.sem); return 0;}/* ----------------------------------------------------------------------------- */struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name){ struct net_device *ndev; struct sir_dev *dev; IRDA_DEBUG(0, "%s - %s\n", __FUNCTION__, name); /* instead of adding tests to protect against drv->do_write==NULL * at several places we refuse to create a sir_dev instance for * drivers which don't implement do_write. */ if (!drv || !drv->do_write) return NULL; /* * Allocate new instance of the device */ ndev = alloc_irdadev(sizeof(*dev)); if (ndev == NULL) { ERROR("%s - Can't allocate memory for IrDA control block!\n", __FUNCTION__); goto out; } dev = ndev->priv; irda_init_max_qos_capabilies(&dev->qos); dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; dev->qos.min_turn_time.bits = drv->qos_mtt_bits; irda_qos_bits_to_value(&dev->qos); strncpy(dev->hwname, name, sizeof(dev->hwname)-1); atomic_set(&dev->enable_rx, 0); dev->tx_skb = NULL; spin_lock_init(&dev->tx_lock); init_MUTEX(&dev->fsm.sem); INIT_LIST_HEAD(&dev->fsm.rq.lh_request); dev->fsm.rq.pending = 0; init_timer(&dev->fsm.rq.timer); dev->drv = drv; dev->netdev = ndev; SET_MODULE_OWNER(ndev); /* Override the network functions we need to use */ ndev->hard_start_xmit = sirdev_hard_xmit; ndev->open = sirdev_open; ndev->stop = sirdev_close; ndev->get_stats = sirdev_get_stats; ndev->do_ioctl = sirdev_ioctl; if (register_netdev(ndev)) { ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); goto out_freenetdev; } return dev;out_freenetdev: free_netdev(ndev);out: return NULL;}int sirdev_put_instance(struct sir_dev *dev){ int err = 0; IRDA_DEBUG(0, "%s\n", __FUNCTION__); atomic_set(&dev->enable_rx, 0); netif_carrier_off(dev->netdev); netif_device_detach(dev->netdev); if (dev->dongle_drv) err = sirdev_schedule_dongle_close(dev); if (err) ERROR("%s - error %d\n", __FUNCTION__, err); sirdev_close(dev->netdev); down(&dev->fsm.sem); dev->fsm.state = SIRDEV_STATE_DEAD; /* mark staled */ dev->dongle_drv = NULL; dev->priv = NULL; up(&dev->fsm.sem); /* Remove netdevice */ unregister_netdev(dev->netdev); free_netdev(dev->netdev); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -