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

📄 stir4200.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (unlikely(skb)) {		WARN_ON(1);		dev_kfree_skb(skb);	}	return 0;}/* * Wait for the transmit FIFO to have space for next data * * If space < 0 then wait till FIFO completely drains. * FYI: can take up to 13 seconds at 2400baud. */static int fifo_txwait(struct stir_cb *stir, int space){	int err;	unsigned long count, status;	/* Read FIFO status and count */	for(;;) {		err = read_reg(stir, REG_FIFOCTL, stir->fifo_status, 				   FIFO_REGS_SIZE);		if (unlikely(err != FIFO_REGS_SIZE)) {			warn("%s: FIFO register read error: %d", 			     stir->netdev->name, err);			return err;		}		status = stir->fifo_status[0];		count = (unsigned)(stir->fifo_status[2] & 0x1f) << 8 			| stir->fifo_status[1];		pr_debug("fifo status 0x%lx count %lu\n", status, count);		/* is fifo receiving already, or empty */		if (!(status & FIFOCTL_DIR)		    || (status & FIFOCTL_EMPTY))			return 0;		if (signal_pending(current))			return -EINTR;		/* shutting down? */		if (!netif_running(stir->netdev)		    || !netif_device_present(stir->netdev))			return -ESHUTDOWN;		/* only waiting for some space */		if (space >= 0 && STIR_FIFO_SIZE - 4 > space + count)			return 0;		/* estimate transfer time for remaining chars */		msleep((count * 8000) / stir->speed);	}				err = write_reg(stir, REG_FIFOCTL, FIFOCTL_CLR);	if (err) 		return err;	err = write_reg(stir, REG_FIFOCTL, 0);	if (err)		return err;	return 0;}/* Wait for turnaround delay before starting transmit.  */static void turnaround_delay(const struct stir_cb *stir, long us){	long ticks;	struct timeval now;	if (us <= 0)		return;	do_gettimeofday(&now);	if (now.tv_sec - stir->rx_time.tv_sec > 0)		us -= USEC_PER_SEC;	us -= now.tv_usec - stir->rx_time.tv_usec;	if (us < 10)		return;	ticks = us / (1000000 / HZ);	if (ticks > 0)		schedule_timeout_interruptible(1 + ticks);	else		udelay(us);}/* * Start receiver by submitting a request to the receive pipe. * If nothing is available it will return after rx_interval. */static int receive_start(struct stir_cb *stir){	/* reset state */	stir->receiving = 1;	stir->rx_buff.in_frame = FALSE;	stir->rx_buff.state = OUTSIDE_FRAME;	stir->rx_urb->status = 0;	return usb_submit_urb(stir->rx_urb, GFP_KERNEL);}/* Stop all pending receive Urb's */static void receive_stop(struct stir_cb *stir){	stir->receiving = 0;	usb_kill_urb(stir->rx_urb);	if (stir->rx_buff.in_frame) 		stir->stats.collisions++;}/* * Wrap data in socket buffer and send it. */static void stir_send(struct stir_cb *stir, struct sk_buff *skb){	unsigned wraplen;	int first_frame = 0;	/* if receiving, need to turnaround */	if (stir->receiving) {		receive_stop(stir);		turnaround_delay(stir, irda_get_mtt(skb));		first_frame = 1;	}	if (isfir(stir->speed))		wraplen = wrap_fir_skb(skb, stir->io_buf);	else		wraplen = wrap_sir_skb(skb, stir->io_buf);			/* check for space available in fifo */	if (!first_frame)		fifo_txwait(stir, wraplen);	stir->stats.tx_packets++;	stir->stats.tx_bytes += skb->len;	stir->netdev->trans_start = jiffies;	pr_debug("send %d (%d)\n", skb->len, wraplen);	if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1),			 stir->io_buf, wraplen,			 NULL, TRANSMIT_TIMEOUT))		stir->stats.tx_errors++;}/* * Transmit state machine thread */static int stir_transmit_thread(void *arg){	struct stir_cb *stir = arg;	struct net_device *dev = stir->netdev;	struct sk_buff *skb;        while (!kthread_should_stop()) {#ifdef CONFIG_PM		/* if suspending, then power off and wait */		if (unlikely(freezing(current))) {			if (stir->receiving)				receive_stop(stir);			else				fifo_txwait(stir, -1);			write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD);			refrigerator();			if (change_speed(stir, stir->speed))				break;		}#endif		/* if something to send? */		skb = xchg(&stir->tx_pending, NULL);		if (skb) {			unsigned new_speed = irda_get_next_speed(skb);			netif_wake_queue(dev);			if (skb->len > 0)				stir_send(stir, skb);			dev_kfree_skb(skb);			if ((new_speed != -1) && (stir->speed != new_speed)) {				if (fifo_txwait(stir, -1) ||				    change_speed(stir, new_speed))					break;			}			continue;		}		/* nothing to send? start receiving */		if (!stir->receiving 		    && irda_device_txqueue_empty(dev)) {			/* Wait otherwise chip gets confused. */			if (fifo_txwait(stir, -1))				break;			if (unlikely(receive_start(stir))) {				if (net_ratelimit())					info("%s: receive usb submit failed",					     stir->netdev->name);				stir->receiving = 0;				msleep(10);				continue;			}		}		/* sleep if nothing to send */                set_current_state(TASK_INTERRUPTIBLE);                schedule();	}        return 0;}/* * USB bulk receive completion callback. * Wakes up every ms (usb round trip) with wrapped  * data. */static void stir_rcv_irq(struct urb *urb){	struct stir_cb *stir = urb->context;	int err;	/* in process of stopping, just drop data */	if (!netif_running(stir->netdev))		return;	/* unlink, shutdown, unplug, other nasties */	if (urb->status != 0) 		return;	if (urb->actual_length > 0) {		pr_debug("receive %d\n", urb->actual_length);		unwrap_chars(stir, urb->transfer_buffer,			     urb->actual_length);				stir->netdev->last_rx = jiffies;		do_gettimeofday(&stir->rx_time);	}	/* kernel thread is stopping receiver don't resubmit */	if (!stir->receiving)		return;	/* resubmit existing urb */	err = usb_submit_urb(urb, GFP_ATOMIC);	/* in case of error, the kernel thread will restart us */	if (err) {		warn("%s: usb receive submit error: %d",			stir->netdev->name, err);		stir->receiving = 0;		wake_up_process(stir->thread);	}}/* * Function stir_net_open (dev) * *    Network device is taken up. Usually this is done by "ifconfig irda0 up" */static int stir_net_open(struct net_device *netdev){	struct stir_cb *stir = netdev_priv(netdev);	int err;	char hwname[16];	err = usb_clear_halt(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1));	if (err)		goto err_out1;	err = usb_clear_halt(stir->usbdev, usb_rcvbulkpipe(stir->usbdev, 2));	if (err)		goto err_out1;	err = change_speed(stir, 9600);	if (err)		goto err_out1;	err = -ENOMEM;	/* Initialize for SIR/FIR to copy data directly into skb.  */	stir->receiving = 0;	stir->rx_buff.truesize = IRDA_SKB_MAX_MTU;	stir->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);	if (!stir->rx_buff.skb) 		goto err_out1;	skb_reserve(stir->rx_buff.skb, 1);	stir->rx_buff.head = stir->rx_buff.skb->data;	do_gettimeofday(&stir->rx_time);	stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!stir->rx_urb) 		goto err_out2;	stir->io_buf = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL);	if (!stir->io_buf)		goto err_out3;	usb_fill_bulk_urb(stir->rx_urb, stir->usbdev,			  usb_rcvbulkpipe(stir->usbdev, 2),			  stir->io_buf, STIR_FIFO_SIZE,			  stir_rcv_irq, stir);	stir->fifo_status = kmalloc(FIFO_REGS_SIZE, GFP_KERNEL);	if (!stir->fifo_status) 		goto err_out4;			/*	 * Now that everything should be initialized properly,	 * Open new IrLAP layer instance to take care of us...	 * Note : will send immediately a speed change...	 */	sprintf(hwname, "usb#%d", stir->usbdev->devnum);	stir->irlap = irlap_open(netdev, &stir->qos, hwname);	if (!stir->irlap) {		err("stir4200: irlap_open failed");		goto err_out5;	}	/** Start kernel thread for transmit.  */	stir->thread = kthread_run(stir_transmit_thread, stir,				   "%s", stir->netdev->name);        if (IS_ERR(stir->thread)) {                err = PTR_ERR(stir->thread);		err("stir4200: unable to start kernel thread");		goto err_out6;	}	netif_start_queue(netdev);	return 0; err_out6:	irlap_close(stir->irlap); err_out5:	kfree(stir->fifo_status); err_out4:	kfree(stir->io_buf); err_out3:	usb_free_urb(stir->rx_urb); err_out2:	kfree_skb(stir->rx_buff.skb); err_out1:	return err;}/* * Function stir_net_close (stir) * *    Network device is taken down. Usually this is done by *    "ifconfig irda0 down" */static int stir_net_close(struct net_device *netdev){	struct stir_cb *stir = netdev_priv(netdev);	/* Stop transmit processing */	netif_stop_queue(netdev);	/* Kill transmit thread */	kthread_stop(stir->thread);	kfree(stir->fifo_status);	/* Mop up receive urb's */	usb_kill_urb(stir->rx_urb);		kfree(stir->io_buf);	usb_free_urb(stir->rx_urb);	kfree_skb(stir->rx_buff.skb);	/* Stop and remove instance of IrLAP */	if (stir->irlap)		irlap_close(stir->irlap);	stir->irlap = NULL;	return 0;}/* * IOCTLs : Extra out-of-band network commands... */static int stir_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd){	struct if_irda_req *irq = (struct if_irda_req *) rq;	struct stir_cb *stir = netdev_priv(netdev);	int ret = 0;	switch (cmd) {	case SIOCSBANDWIDTH: /* Set bandwidth */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		/* Check if the device is still there */		if (netif_device_present(stir->netdev))			ret = change_speed(stir, irq->ifr_baudrate);		break;	case SIOCSMEDIABUSY: /* Set media busy */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		/* Check if the IrDA stack is still there */		if (netif_running(stir->netdev))			irda_device_set_media_busy(stir->netdev, TRUE);		break;	case SIOCGRECEIVING:		/* Only approximately true */		irq->ifr_receiving = stir->receiving;		break;	default:		ret = -EOPNOTSUPP;	}	return ret;}/* * Get device stats (for /proc/net/dev and ifconfig) */static struct net_device_stats *stir_net_get_stats(struct net_device *netdev){	struct stir_cb *stir = netdev_priv(netdev);	return &stir->stats;}/* * This routine is called by the USB subsystem for each new device * in the system. We need to check if the device is ours, and in * this case start handling it. * Note : it might be worth protecting this function by a global * spinlock... Or not, because maybe USB already deal with that... */static int stir_probe(struct usb_interface *intf,		      const struct usb_device_id *id){	struct usb_device *dev = interface_to_usbdev(intf);	struct stir_cb *stir = NULL;	struct net_device *net;	int ret = -ENOMEM;	/* Allocate network device container. */	net = alloc_irdadev(sizeof(*stir));	if(!net)		goto err_out1;	SET_MODULE_OWNER(net);	SET_NETDEV_DEV(net, &intf->dev);	stir = netdev_priv(net);	stir->netdev = net;	stir->usbdev = dev;	ret = usb_reset_configuration(dev);	if (ret != 0) {		err("stir4200: usb reset configuration failed");		goto err_out2;	}	printk(KERN_INFO "SigmaTel STIr4200 IRDA/USB found at address %d, "		"Vendor: %x, Product: %x\n",	       dev->devnum, le16_to_cpu(dev->descriptor.idVendor),	       le16_to_cpu(dev->descriptor.idProduct));	/* Initialize QoS for this device */	irda_init_max_qos_capabilies(&stir->qos);	/* That's the Rx capability. */	stir->qos.baud_rate.bits       &= IR_2400 | IR_9600 | IR_19200 |					 IR_38400 | IR_57600 | IR_115200 |					 (IR_4000000 << 8);	stir->qos.min_turn_time.bits   &= qos_mtt_bits;	irda_qos_bits_to_value(&stir->qos);	/* Override the network functions we need to use */	net->hard_start_xmit = stir_hard_xmit;	net->open            = stir_net_open;	net->stop            = stir_net_close;	net->get_stats	     = stir_net_get_stats;	net->do_ioctl        = stir_net_ioctl;	ret = register_netdev(net);	if (ret != 0)		goto err_out2;	info("IrDA: Registered SigmaTel device %s", net->name);	usb_set_intfdata(intf, stir);	return 0;err_out2:	free_netdev(net);err_out1:	return ret;}/* * The current device is removed, the USB layer tell us to shut it down... */static void stir_disconnect(struct usb_interface *intf){	struct stir_cb *stir = usb_get_intfdata(intf);	if (!stir)		return;	unregister_netdev(stir->netdev);	free_netdev(stir->netdev);	usb_set_intfdata(intf, NULL);}#ifdef CONFIG_PM/* USB suspend, so power off the transmitter/receiver */static int stir_suspend(struct usb_interface *intf, pm_message_t message){	struct stir_cb *stir = usb_get_intfdata(intf);	netif_device_detach(stir->netdev);	return 0;}/* Coming out of suspend, so reset hardware */static int stir_resume(struct usb_interface *intf){	struct stir_cb *stir = usb_get_intfdata(intf);	netif_device_attach(stir->netdev);	/* receiver restarted when send thread wakes up */	return 0;}#endif/* * USB device callbacks */static struct usb_driver irda_driver = {	.name		= "stir4200",	.probe		= stir_probe,	.disconnect	= stir_disconnect,	.id_table	= dongles,#ifdef CONFIG_PM	.suspend	= stir_suspend,	.resume		= stir_resume,#endif};/* * Module insertion */static int __init stir_init(void){	return usb_register(&irda_driver);}module_init(stir_init);/* * Module removal */static void __exit stir_cleanup(void){	/* Deregister the driver and remove all pending instances */	usb_deregister(&irda_driver);}module_exit(stir_cleanup);

⌨️ 快捷键说明

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