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

📄 usb-func.c

📁 ARM嵌入式应用开发典型实例配书光盘,希望对你有用!
💻 C
📖 第 1 页 / 共 2 页
字号:
	else
		rv = 0;
	
	dbg("Leave");
	return rv;
}

static int go_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	pusb_t s;
	s = (pusb_t) file->private_data;

	err("ioctl %x %x", cmd, arg);
	
	if(cmd != IOCTL_GO_COMMAND) {
		err("cmd != IOCTL_GO_COMMAND");
		return 0;
	}
	err("will OnIoctlProc");

	return OnIoctlProc(s, arg);
}

static int go_open (struct inode *inode, struct file *file)
{
	pusb_t s;
	int minor;
	int rv;

	dbg("Enter");

	rv = 0;
	minor = MINOR(inode->i_rdev);
	dbg("minor = %d", minor);

	if(minor < 0 || minor >= MAX_DEVICES){
		return -ENODEV;
	}

	down(&usb_dev_table_mutex);

	s = usb_dev_table[minor];

	if(s == NULL){
		err("device (%d) not exist", minor);
		up(&usb_dev_table_mutex);
		return -ENODEV;
	}

	if (s->DeviceState != DS_IDLE){
		err("ERROR: device is nod IDLE");
		rv = -EIO;
		goto exit;
	}

	down (&s->mutex);

	s->opened = 1;

	file->f_pos = 0;
	file->private_data = s;
	s->open_count++;

	StreamBuffer_Init(&(s->StreamBuffer));

	s->DeviceState = DS_OPENED;
	s->rd_irq_data.allow_irq = 1;

	up(&s->mutex);

exit:
	up(&usb_dev_table_mutex);

	dbg("Leave");
	return rv;
}

static int go_release (struct inode *inode, struct file *file)
{
	pusb_t s;
	int rv;

	dbg("Enter");

	s = (pusb_t) file->private_data;
	
	/* Lock minor table and our device */
	down(&usb_dev_table_mutex);
	down(&s->mutex);

	if(s->DeviceState != DS_OPENED && s->DeviceState != DS_RUNNING){
		rv = -ENODEV;
		goto exit;
	}

	lock_kernel();

	s->opened = 0;
	StreamBuffer_Uninit(&(s->StreamBuffer));
	
	unlock_kernel();

	if(s->usbdev == NULL){
		up(&s->mutex);
		go_delete(s);
		up(&usb_dev_table_mutex);
		return 0;
	}

	s->DeviceState = DS_IDLE;
	s->rd_irq_data.allow_irq = 0;

exit:
	up(&s->mutex);
	up(&usb_dev_table_mutex);

	dbg("Leave");
	return 0;
}
/*
static struct file_operations go_fops =
{
	owner:		THIS_MODULE,
	read:		go_read,
	write:		go_write,
	open:		go_open,
	release:	go_release,
};
*/

static struct file_operations go_fops =
{
	owner:		THIS_MODULE,
	read:		go_read,
	write:		go_write,
	ioctl:		go_ioctl,
	open:		go_open,
	release:	go_release,
};


/* --------------------------------------------------------------------- */
static void *go_probe (struct usb_device *usbdev, unsigned int ifnum,
			   const struct usb_device_id *id)
{
	int i;
	int minor;
	struct usb_endpoint_descriptor *pEP;
	pusb_t s = NULL;

	dbg("Enter");
	
	dbg("vendor id 0x%x, device id 0x%x ifnum:%d",
		usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);

	/* We don't handle multiple configurations */
	if (usbdev->descriptor.bNumConfigurations != 1)
		return NULL;

	down(&usb_dev_table_mutex);

	minor = GODEV_MINOR(usbdev->bus->busnum, usbdev->devnum);
	info("go_probe: Device %d on Bus %d, minor = %d",
		  usbdev->devnum, usbdev->bus->busnum, minor);

	if(minor < 0 || minor >= 256) {
		err("Invalid minor: %d", minor);
		goto failed;
	}

	if(usb_dev_table[minor] != NULL) {
		err("ERROR: minor conflict");
		goto failed;
	}

	/* Allocate dev data structure */
	s = kmalloc(sizeof(usb_t), GFP_KERNEL);
	if(s == NULL){
		err("Out of memory");
		goto failed;
	}
	usb_dev_table[minor] = s;

	/* Initialization */
	memset (s, 0, sizeof (usb_t));

	init_MUTEX (&s->mutex);
	s->usbdev				= usbdev;
	s->minor				= minor;
	s->total_buffer_size	= buffers;

	s->bh.func	= read_stream_bh;
	s->bh.data	= (unsigned long) s;

	sprintf(s->StreamBuffer.cachename, "DEV%d", minor);

	init_waitqueue_head(&s->wq_control_pipe);
	init_waitqueue_head(&s->wq_download_pipe);
	init_waitqueue_head(&s->wq_stream_pipe);
	init_waitqueue_head(&s->wq_interrupt_pipe);
	init_waitqueue_head(&s->wq_stop_stream_thread);

	init_waitqueue_head(&s->wait);
	init_waitqueue_head(&s->remove_ok);

	spin_lock_init(&s->lock);
	INIT_LIST_HEAD(&s->free_buff_list);
	INIT_LIST_HEAD(&s->rec_buff_list);

	/* ----------- */
	down (&s->mutex);

	/* Enumerate endpoints */
	for(i=0;i<usbdev->config[0].interface[0].altsetting[0].bNumEndpoints;i++) {
		pEP = &(usbdev->config[0].interface[0].altsetting[0].endpoint[i]);
		dbg("------- %d 0x%02x %02d %x %d",
			pEP->bDescriptorType,
			pEP->bEndpointAddress,
			pEP->wMaxPacketSize,
			pEP->bmAttributes, pEP->bInterval);

		if((pEP->bEndpointAddress & 0x80) &&
			((pEP->bmAttributes & 3) == 0x02)) {
				/* we found a bulk in endpoint */
				s->bulk_in_buffer = kmalloc(BULK_IN_BUFSIZE, GFP_KERNEL);
				s->bulkin_urb	  = usb_alloc_urb(0);
		}

		if(((pEP->bEndpointAddress & 0x80) == 0x00) &&
			((pEP->bmAttributes & 3) == 0x02)) {
				/* we found a bulk out endpoint */
				s->bulk_out_size = pEP->wMaxPacketSize;
		}
	}

	s->remove_pending	= 0;
	s->usbdev			= usbdev;

	/* Pre-allocate Interrupt URB */
	s->irq_urb	= usb_alloc_urb(0);
	s->irq_buf	= kmalloc(4, GFP_KERNEL);

	FILL_INT_URB(s->irq_urb, s->usbdev, 
				 usb_rcvintpipe(s->usbdev, INTERRUPT_PIPE),
				 s->irq_buf, 4,
				 interrupt_pipe_complete, s, 0x40);
	s->irq_urb->transfer_flags = 0x10;

	{
		int rv;

		s->rd_irq_data.ready     = 0;
		s->rd_irq_data.allow_irq = 0;
		rv = usb_submit_urb(s->irq_urb);
		dbg("usb_submit_urb: %d\n", rv);
	}

#if 0
	if (usb_set_configuration (usbdev, usbdev->config[0].bConfigurationValue) < 0) {
		err("set_configuration failed");
		goto failed;
	}
#endif
	
	/* --------- */
	up (&s->mutex);

	s->DeviceState = DS_IDLE;

	up(&usb_dev_table_mutex);

	dbg("Leave (successful)");
	return s;

failed:
	up(&usb_dev_table_mutex);

	dbg("Leave (probe failed)");
	return NULL;
}

static void go_disconnect (struct usb_device *usbdev, void *ptr)
{
	int minor;
	pusb_t s = (pusb_t) ptr;

	dbg("Enter");

	down (&s->mutex);

	minor = s->minor;

	s->remove_pending = 1;
	wake_up (&s->wait);

	s->usbdev = NULL;
	s->overruns = 0;

	if(s->irq_urb)
	{
		dbg("Unlink IRQ URB");
		usb_unlink_urb(s->irq_urb);
		usb_free_urb(s->irq_urb);
	}

	if(s->bulkin_urb)
	{
		dbg("Unlink Bulk-In URB");
		usb_unlink_urb(s->bulkin_urb);
		usb_free_urb(s->bulkin_urb);
	}

	if(s->DeviceState == DS_IDLE){
		up(&s->mutex);
		go_delete(s);
	} else {
		s->usbdev = NULL;
		up(&s->mutex);
	}

	info("GO7007 #%d now disconnected", minor);
	dbg("Leave");
}

static struct usb_device_id go_ids [] = {
//	{ USB_DEVICE(0x0547, 0x1002) },
	{ USB_DEVICE(0x0EB1, 0x7007) },
	{ }						/* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, go_ids);

static struct usb_driver go_driver =
{
	name:			"go",
	probe:			go_probe,
	disconnect:		go_disconnect,
	id_table:		go_ids,
};

/* --------------------------------------------------------------------- */

static int __init go_init (void)
{
	int rv;
	unsigned u;

	/* initialize struct */
	for (u = 0; u < MAX_DEVICES; u++){
		usb_dev_table[u] = NULL;
	}

	/* Register devfs device*/
	rv = devfs_register_chrdev(USB_GO_MAJOR,
				"go7007", &go_fops);

	if(rv){
		err("failed to register devfs device. Error number %d", rv);
		return -1;
	}

	/* Register usb device */
	rv = usb_register(&go_driver);
	if(rv){
		err("usb_register failed. Error number %d", rv);
		return -1;
	}

	dbg("usb_init: driver registered");

	info(DRIVER_DESC " " DRIVER_VERSION);
	return 0;
}

static void __exit go_cleanup (void)
{
	dbg("usb_cleanup");

	usb_deregister (&go_driver);
	devfs_unregister_chrdev(USB_GO_MAJOR, "go7007");
}

/* --------------------------------------------------------------------- */

MODULE_AUTHOR ("JUN DING & HONGJUN YUAN");
MODULE_DESCRIPTION (" GO 7007 Driver for Linux (c)2002");
MODULE_PARM (buffers, "i");
MODULE_PARM_DESC (buffers, "Number of buffers (default=256)");
MODULE_LICENSE("-Tech");

module_init (go_init);
module_exit (go_cleanup);

⌨️ 快捷键说明

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