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

📄 stir4200.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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);		/* error when receive/transmit fifo gets confused */		if (status & FIFOCTL_RXERR) {			stir->stats.rx_fifo_errors++;			stir->stats.rx_errors++;			break;		}		if (status & FIFOCTL_TXERR) {			stir->stats.tx_fifo_errors++;			stir->stats.tx_errors++;			break;		}		/* 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);	us -= (now.tv_sec - stir->rx_time.tv_sec) * USEC_PER_SEC;	us -= now.tv_usec - stir->rx_time.tv_usec;	if (us < 10)		return;	ticks = us / (1000000 / HZ);	if (ticks > 0) {		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(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_unlink_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, msecs_to_jiffies(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;	daemonize("%s", dev->name);	allow_signal(SIGTERM);	while (netif_running(dev)	       && netif_device_present(dev)	       && !signal_pending(current))	{		/* if suspending, then power off and wait */		if (current->flags & PF_FREEZE) {			if (stir->receiving)				receive_stop(stir);			else				fifo_txwait(stir, -1);			write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD);			refrigerator(PF_FREEZE);			if (change_speed(stir, stir->speed))				break;		}		/* 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 (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 */		wait_event_interruptible(stir->thr_wait, stir->tx_pending);	}	complete_and_exit (&stir->thr_exited, 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 pt_regs *regs){	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(&stir->thr_wait);	}}/* * 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;	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("irlap_open failed");		goto err_out5;	}	/** Start kernel thread for transmit.  */	stir->thr_pid = kernel_thread(stir_transmit_thread, stir,				      CLONE_FS|CLONE_FILES);	if (stir->thr_pid < 0) {		err = stir->thr_pid;		err("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;	/* Stop transmit processing */	netif_stop_queue(netdev);	/* Kill transmit thread */	kill_proc(stir->thr_pid, SIGTERM, 1);	wait_for_completion(&stir->thr_exited);	kfree(stir->fifo_status);	/* Mop up receive urb's */	usb_unlink_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 *dev, struct ifreq *rq, int cmd){	struct if_irda_req *irq = (struct if_irda_req *) rq;	struct stir_cb *stir = dev->priv;	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 *dev){	struct stir_cb *stir = dev->priv;	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 = net->priv;	stir->netdev = net;	stir->usbdev = dev;	ret = usb_reset_configuration(dev);	if (ret != 0) {		err("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, dev->descriptor.idVendor,	       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);	init_completion (&stir->thr_exited);	init_waitqueue_head (&stir->thr_wait);	/* 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;	MESSAGE("IrDA: Registered SigmaTel device %s\n", 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);}/* Power management suspend, so power off the transmitter/receiver */static int stir_suspend(struct usb_interface *intf, u32 state){	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;}/* * USB device callbacks */static struct usb_driver irda_driver = {	.owner		= THIS_MODULE,	.name		= "stir4200",	.probe		= stir_probe,	.disconnect	= stir_disconnect,	.id_table	= dongles,	.suspend	= stir_suspend,	.resume		= stir_resume,};/* * Module insertion */static int __init stir_init(void){	if (usb_register(&irda_driver) < 0)		return -1;	MESSAGE("SigmaTel support registered\n");	return 0;}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 + -