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

📄 mcs7780.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (!mcs->tx_urb)		return 0;	mcs->rx_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!mcs->rx_urb)		return 0;	return 1;}/* Sets up state to be initially outside frame, gets receive urb, * sets status to successful and then submits the urb to start * receiving the data. */static inline int mcs_receive_start(struct mcs_cb *mcs){	mcs->rx_buff.in_frame = FALSE;	mcs->rx_buff.state = OUTSIDE_FRAME;	usb_fill_bulk_urb(mcs->rx_urb, mcs->usbdev,			  usb_rcvbulkpipe(mcs->usbdev, mcs->ep_in),			  mcs->in_buf, 4096, mcs_receive_irq, mcs);	mcs->rx_urb->status = 0;	return usb_submit_urb(mcs->rx_urb, GFP_KERNEL);}/* Finds the in and out endpoints for the mcs control block */static inline int mcs_find_endpoints(struct mcs_cb *mcs,				     struct usb_host_endpoint *ep, int epnum){	int i;	int ret = 0;	/* If no place to store the endpoints just return */	if (!ep)		return ret;	/* cycle through all endpoints, find the first two that are DIR_IN */	for (i = 0; i < epnum; i++) {		if (ep[i].desc.bEndpointAddress & USB_DIR_IN)			mcs->ep_in = ep[i].desc.bEndpointAddress;		else			mcs->ep_out = ep[i].desc.bEndpointAddress;		/* MosChip says that the chip has only two bulk		 * endpoints. Find one for each direction and move on.		 */		if ((mcs->ep_in != 0) && (mcs->ep_out != 0)) {			ret = 1;			break;		}	}	return ret;}static void mcs_speed_work(struct work_struct *work){	struct mcs_cb *mcs = container_of(work, struct mcs_cb, work);	struct net_device *netdev = mcs->netdev;	mcs_speed_change(mcs);	netif_wake_queue(netdev);}/* Function to change the speed of the mcs7780.  Fully supports SIR, * MIR, and FIR speeds. */static int mcs_speed_change(struct mcs_cb *mcs){	int ret = 0;	int rst = 0;	int cnt = 0;	__u16 nspeed;	__u16 rval;	nspeed = mcs_speed_set[(mcs->new_speed >> 8) & 0x0f];	do {		mcs_get_reg(mcs, MCS_RESV_REG, &rval);	} while(cnt++ < 100 && (rval & MCS_IRINTX));	if(cnt >= 100) {		IRDA_ERROR("unable to change speed");		ret = -EIO;		goto error;	}	mcs_get_reg(mcs, MCS_MODE_REG, &rval);	/* MINRXPW values recomended by MosChip */	if (mcs->new_speed <= 115200) {		rval &= ~MCS_FIR;		if ((rst = (mcs->speed > 115200)))			mcs_set_reg(mcs, MCS_MINRXPW_REG, 0);	} else if (mcs->new_speed <= 1152000) {		rval &= ~MCS_FIR;		if ((rst = !(mcs->speed == 576000 || mcs->speed == 1152000)))			mcs_set_reg(mcs, MCS_MINRXPW_REG, 5);	} else {		rval |= MCS_FIR;		if ((rst = (mcs->speed != 4000000)))			mcs_set_reg(mcs, MCS_MINRXPW_REG, 5);	}	rval &= ~MCS_SPEED_MASK;	rval |= nspeed;	ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);	if (unlikely(ret))		goto error;	if (rst)		switch (mcs->transceiver_type) {		case MCS_TSC_VISHAY:			ret = mcs_setup_transceiver_vishay(mcs);			break;		case MCS_TSC_SHARP:			ret = mcs_setup_transceiver_sharp(mcs);			break;		case MCS_TSC_AGILENT:			ret = mcs_setup_transceiver_agilent(mcs);			break;		default:			ret = 1;			IRDA_WARNING("Unknown transceiver type: %d",				     mcs->transceiver_type);		}	if (unlikely(ret))		goto error;	mcs_get_reg(mcs, MCS_MODE_REG, &rval);	rval &= ~MCS_RESET;	ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);	mcs->speed = mcs->new_speed;	error:		mcs->new_speed = 0;		return ret;}/* Ioctl calls not supported at this time.  Can be an area of future work. */static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd){	/* struct if_irda_req *irq = (struct if_irda_req *)rq; */	/* struct mcs_cb *mcs = netdev_priv(netdev); */	int ret = 0;	switch (cmd) {	default:		ret = -EOPNOTSUPP;	}	return ret;}/* Network device is taken down, done by "ifconfig irda0 down" */static int mcs_net_close(struct net_device *netdev){	int ret = 0;	struct mcs_cb *mcs = netdev_priv(netdev);	/* Stop transmit processing */	netif_stop_queue(netdev);	/* kill and free the receive and transmit URBs */	usb_kill_urb(mcs->rx_urb);	usb_free_urb(mcs->rx_urb);	usb_kill_urb(mcs->tx_urb);	usb_free_urb(mcs->tx_urb);	/* Stop and remove instance of IrLAP */	if (mcs->irlap)		irlap_close(mcs->irlap);	mcs->irlap = NULL;	return ret;}/* Network device is taken up, done by "ifconfig irda0 up" */static int mcs_net_open(struct net_device *netdev){	struct mcs_cb *mcs = netdev_priv(netdev);	char hwname[16];	int ret = 0;	ret = usb_clear_halt(mcs->usbdev,			     usb_sndbulkpipe(mcs->usbdev, mcs->ep_in));	if (ret)		goto error1;	ret = usb_clear_halt(mcs->usbdev,			     usb_rcvbulkpipe(mcs->usbdev, mcs->ep_out));	if (ret)		goto error1;	ret = mcs_setup_transceiver(mcs);	if (ret)		goto error1;	ret = -ENOMEM;	/* Initialize for SIR/FIR to copy data directly into skb.  */	mcs->receiving = 0;	mcs->rx_buff.truesize = IRDA_SKB_MAX_MTU;	mcs->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);	if (!mcs->rx_buff.skb)		goto error1;	skb_reserve(mcs->rx_buff.skb, 1);	mcs->rx_buff.head = mcs->rx_buff.skb->data;	do_gettimeofday(&mcs->rx_time);	/*	 * 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", mcs->usbdev->devnum);	mcs->irlap = irlap_open(netdev, &mcs->qos, hwname);	if (!mcs->irlap) {		IRDA_ERROR("mcs7780: irlap_open failed");		goto error2;	}	if (!mcs_setup_urbs(mcs))	goto error3;	ret = mcs_receive_start(mcs);	if (ret)		goto error3;	netif_start_queue(netdev);	return 0;	error3:		irlap_close(mcs->irlap);	error2:		kfree_skb(mcs->rx_buff.skb);	error1:		return ret;}/* Get device stats for /proc/net/dev and ifconfig */static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev){	struct mcs_cb *mcs = netdev_priv(netdev);	return &mcs->stats;}/* Receive callback function.  */static void mcs_receive_irq(struct urb *urb){	__u8 *bytes;	struct mcs_cb *mcs = urb->context;	int i;	int ret;	if (!netif_running(mcs->netdev))		return;	if (urb->status)		return;	if (urb->actual_length > 0) {		bytes = urb->transfer_buffer;		/* MCS returns frames without BOF and EOF		 * I assume it returns whole frames.		 */		/* SIR speed */		if(mcs->speed < 576000) {			async_unwrap_char(mcs->netdev, &mcs->stats,				  &mcs->rx_buff, 0xc0);			for (i = 0; i < urb->actual_length; i++)				async_unwrap_char(mcs->netdev, &mcs->stats,					  &mcs->rx_buff, bytes[i]);			async_unwrap_char(mcs->netdev, &mcs->stats,				  &mcs->rx_buff, 0xc1);		}		/* MIR speed */		else if(mcs->speed == 576000 || mcs->speed == 1152000) {			mcs_unwrap_mir(mcs, urb->transfer_buffer,				urb->actual_length);		}		/* FIR speed */		else {			mcs_unwrap_fir(mcs, urb->transfer_buffer,				urb->actual_length);		}		mcs->netdev->last_rx = jiffies;		do_gettimeofday(&mcs->rx_time);	}	ret = usb_submit_urb(urb, GFP_ATOMIC);}/* Transmit callback funtion.  */static void mcs_send_irq(struct urb *urb){	struct mcs_cb *mcs = urb->context;	struct net_device *ndev = mcs->netdev;	if (unlikely(mcs->new_speed))		schedule_work(&mcs->work);	else		netif_wake_queue(ndev);}/* Transmit callback funtion.  */static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev){	unsigned long flags;	struct mcs_cb *mcs;	int wraplen;	int ret = 0;	if (skb == NULL || ndev == NULL)		return -EINVAL;	netif_stop_queue(ndev);	mcs = netdev_priv(ndev);	spin_lock_irqsave(&mcs->lock, flags);	mcs->new_speed = irda_get_next_speed(skb);	if (likely(mcs->new_speed == mcs->speed))		mcs->new_speed = 0;	/* SIR speed */	if(mcs->speed < 576000) {		wraplen = mcs_wrap_sir_skb(skb, mcs->out_buf);	}	/* MIR speed */	else if(mcs->speed == 576000 || mcs->speed == 1152000) {		wraplen = mcs_wrap_mir_skb(skb, mcs->out_buf);	}	/* FIR speed */	else {		wraplen = mcs_wrap_fir_skb(skb, mcs->out_buf);	}	usb_fill_bulk_urb(mcs->tx_urb, mcs->usbdev,			  usb_sndbulkpipe(mcs->usbdev, mcs->ep_out),			  mcs->out_buf, wraplen, mcs_send_irq, mcs);	if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) {		IRDA_ERROR("failed tx_urb: %d", ret);		switch (ret) {		case -ENODEV:		case -EPIPE:			break;		default:			mcs->stats.tx_errors++;			netif_start_queue(ndev);		}	} else {		mcs->stats.tx_packets++;		mcs->stats.tx_bytes += skb->len;	}	dev_kfree_skb(skb);	spin_unlock_irqrestore(&mcs->lock, flags);	return ret;}/* * This function is called by the USB subsystem for each new device in the * system.  Need to verify the device and if it is, then start handling it. */static int mcs_probe(struct usb_interface *intf,		     const struct usb_device_id *id){	struct usb_device *udev = interface_to_usbdev(intf);	struct net_device *ndev = NULL;	struct mcs_cb *mcs;	int ret = -ENOMEM;	ndev = alloc_irdadev(sizeof(*mcs));	if (!ndev)		goto error1;	IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.", udev->devnum);	/* what is it realy for? */	SET_MODULE_OWNER(ndev);	SET_NETDEV_DEV(ndev, &intf->dev);	ret = usb_reset_configuration(udev);	if (ret != 0) {		IRDA_ERROR("mcs7780: usb reset configuration failed");		goto error2;	}	mcs = netdev_priv(ndev);	mcs->usbdev = udev;	mcs->netdev = ndev;	spin_lock_init(&mcs->lock);	/* Initialize QoS for this device */	irda_init_max_qos_capabilies(&mcs->qos);	/* That's the Rx capability. */	mcs->qos.baud_rate.bits &=	    IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200		| IR_576000 | IR_1152000 | (IR_4000000 << 8);	mcs->qos.min_turn_time.bits &= qos_mtt_bits;	irda_qos_bits_to_value(&mcs->qos);	/* Speed change work initialisation*/	INIT_WORK(&mcs->work, mcs_speed_work);	/* Override the network functions we need to use */	ndev->hard_start_xmit = mcs_hard_xmit;	ndev->open = mcs_net_open;	ndev->stop = mcs_net_close;	ndev->get_stats = mcs_net_get_stats;	ndev->do_ioctl = mcs_net_ioctl;	if (!intf->cur_altsetting)		goto error2;	ret = mcs_find_endpoints(mcs, intf->cur_altsetting->endpoint,				 intf->cur_altsetting->desc.bNumEndpoints);	if (!ret) {		ret = -ENODEV;		goto error2;	}	ret = register_netdev(ndev);	if (ret != 0)		goto error2;	IRDA_DEBUG(1, "IrDA: Registered MosChip MCS7780 device as %s",		   ndev->name);	mcs->transceiver_type = transceiver_type;	mcs->sir_tweak = sir_tweak;	mcs->receive_mode = receive_mode;	usb_set_intfdata(intf, mcs);	return 0;	error2:		free_netdev(ndev);	error1:		return ret;}/* The current device is removed, the USB layer tells us to shut down. */static void mcs_disconnect(struct usb_interface *intf){	struct mcs_cb *mcs = usb_get_intfdata(intf);	if (!mcs)		return;	flush_scheduled_work();	unregister_netdev(mcs->netdev);	free_netdev(mcs->netdev);	usb_set_intfdata(intf, NULL);	IRDA_DEBUG(0, "MCS7780 now disconnected.");}/* Module insertion */static int __init mcs_init(void){	int result;	/* register this driver with the USB subsystem */	result = usb_register(&mcs_driver);	if (result)		IRDA_ERROR("usb_register failed. Error number %d", result);	return result;}module_init(mcs_init);/* Module removal */static void __exit mcs_exit(void){	/* deregister this driver with the USB subsystem */	usb_deregister(&mcs_driver);}module_exit(mcs_exit);

⌨️ 快捷键说明

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