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

📄 scanner.c

📁 linux qt的图形设计实际例子
💻 C
📖 第 1 页 / 共 3 页
字号:

 		nb = le16_to_cpup(&cmsg.req.wLength);

 		if (nb > sizeof(buf))
 			return -EINVAL;

 		if ((cmsg.req.bRequestType & 0x80) == 0) {
 			pipe = usb_sndctrlpipe(dev, 0);
 			if (nb > 0 && copy_from_user(buf, cmsg.data, nb))
 				return -EFAULT;
 		} else {
 			pipe = usb_rcvctrlpipe(dev, 0);
		}

 		ret = usb_control_msg(dev, pipe, cmsg.req.bRequest,
 				      cmsg.req.bRequestType,
 				      le16_to_cpup(&cmsg.req.wValue),
 				      le16_to_cpup(&cmsg.req.wIndex),
 				      buf, nb, HZ);

 		if (ret < 0) {
 			err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
 			return -EIO;
 		}

 		if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
 			return -EFAULT;

 		return 0;
 	}
	default:
		return -ENOTTY;
	}
	return 0;
}

static struct
file_operations usb_scanner_fops = {
	read:		read_scanner,
	write:		write_scanner,
	ioctl:		ioctl_scanner,
	open:		open_scanner,
	release:	close_scanner,
};

static void *
probe_scanner(struct usb_device *dev, unsigned int ifnum,
	      const struct usb_device_id *id)
{
	struct scn_usb_data *scn;
	struct usb_interface_descriptor *interface;
	struct usb_endpoint_descriptor *endpoint;

	int ep_cnt;
	int ix;
	int scn_minor;
	int retval;

	char valid_device = 0;
	char have_bulk_in, have_bulk_out, have_intr;
	char name[10];

	if (vendor != -1 && product != -1) {
		info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
	}

	dbg("probe_scanner: USB dev address:%p", dev);
	dbg("probe_scanner: ifnum:%u", ifnum);

/*
 * 1. Check Vendor/Product
 * 2. Determine/Assign Bulk Endpoints
 * 3. Determine/Assign Intr Endpoint
 */

/*
 * There doesn't seem to be an imaging class defined in the USB
 * Spec. (yet).  If there is, HP isn't following it and it doesn't
 * look like anybody else is either.  Therefore, we have to test the
 * Vendor and Product ID's to see what we have.  Also, other scanners
 * may be able to use this driver by specifying both vendor and
 * product ID's as options to the scanner module in conf.modules.
 *
 * NOTE: Just because a product is supported here does not mean that
 * applications exist that support the product.  It's in the hopes
 * that this will allow developers a means to produce applications
 * that will support USB products.
 *
 * Until we detect a device which is pleasing, we silently punt.
 */

	for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct usb_device_id); ix++) {
		if ((dev->descriptor.idVendor == scanner_device_ids [ix].idVendor) &&
		    (dev->descriptor.idProduct == scanner_device_ids [ix].idProduct)) {
			valid_device = 1;
			break;
                }
	}
	if (dev->descriptor.idVendor == vendor &&   /* User specified */
	    dev->descriptor.idProduct == product) { /* User specified */
		valid_device = 1;
	}

        if (!valid_device)
                return NULL;    /* We didn't find anything pleasing */

/*
 * After this point we can be a little noisy about what we are trying to
 *  configure.
 */

	if (dev->descriptor.bNumConfigurations != 1) {
		info("probe_scanner: Only one device configuration is supported.");
		return NULL;
	}

	if (dev->config[0].bNumInterfaces != 1) {
		info("probe_scanner: Only one device interface is supported.");
		return NULL;
	}

	interface = dev->config[0].interface[ifnum].altsetting;
	endpoint = interface[ifnum].endpoint;

/*
 * Start checking for two bulk endpoints OR two bulk endpoints *and* one
 * interrupt endpoint. If we have an interrupt endpoint go ahead and
 * setup the handler. FIXME: This is a future enhancement...
 */

	dbg("probe_scanner: Number of Endpoints:%d", (int) interface->bNumEndpoints);

	if ((interface->bNumEndpoints != 2) && (interface->bNumEndpoints != 3)) {
		info("probe_scanner: Only two or three endpoints supported.");
		return NULL;
	}

	ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;

	while (ep_cnt < interface->bNumEndpoints) {

		if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) {
			ep_cnt++;
			have_bulk_in = ep_cnt;
			dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
			continue;
		}

		if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) {
			ep_cnt++;
			have_bulk_out = ep_cnt;
			dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
			continue;
		}

		if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) {
			ep_cnt++;
			have_intr = ep_cnt;
			dbg("probe_scanner: intr_ep:%d", have_intr);
			continue;
		}
		info("probe_scanner: Undetected endpoint -- consult Documentation/usb/scanner.txt.");
		return NULL;	/* Shouldn't ever get here unless we have something weird */
	}


/*
 * Perform a quick check to make sure that everything worked as it
 * should have.
 */

	switch(interface->bNumEndpoints) {
	case 2:
		if (!have_bulk_in || !have_bulk_out) {
			info("probe_scanner: Two bulk endpoints required.");
			return NULL;
		}
		break;
	case 3:
		if (!have_bulk_in || !have_bulk_out || !have_intr) {
			info("probe_scanner: Two bulk endpoints and one interrupt endpoint required.");
			return NULL;
		}
		break;
	default:
		info("probe_scanner: Endpoint determination failed --  consult Documentation/usb/scanner.txt");
		return NULL;
	}


/*
 * Determine a minor number and initialize the structure associated
 * with it.  The problem with this is that we are counting on the fact
 * that the user will sequentially add device nodes for the scanner
 * devices.  */
	
	down(&scn_mutex);

	retval = usb_register_dev(&scanner_driver, 1, &scn_minor);
	if (retval) {
		if (retval != -ENODEV) {
			err ("Not able to get a minor for this device.");
			up(&scn_mutex);
			return NULL;
		}
		for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
			if (!p_scn_table[scn_minor])
				break;
		}
	}

/* Check to make sure that the last slot isn't already taken */
	if (p_scn_table[scn_minor]) {
		err("probe_scanner: No more minor devices remaining.");
		up(&scn_mutex);
		return NULL;
	}

	dbg("probe_scanner: Allocated minor:%d", scn_minor);

	if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
		err("probe_scanner: Out of memory.");
		up(&scn_mutex);
		return NULL;
	}
	memset (scn, 0, sizeof(struct scn_usb_data));

	scn->scn_irq = usb_alloc_urb(0, GFP_KERNEL);
	if (!scn->scn_irq) {
		kfree(scn);
		up(&scn_mutex);
		return NULL;
	}

	init_MUTEX(&(scn->sem)); /* Initializes to unlocked */

	dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);

/* Ok, if we detected an interrupt EP, setup a handler for it */
	if (have_intr) {
		dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
		FILL_INT_URB(scn->scn_irq, dev,
			     usb_rcvintpipe(dev, have_intr),
			     &scn->button, 1, irq_scanner, scn,
			     // endpoint[(int)have_intr].bInterval);
			     250);

	        if (usb_submit_urb(scn->scn_irq, GFP_KERNEL)) {
			err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
                	kfree(scn);
			up(&scn_mutex);
                	return NULL;
        	}
	}


/* Ok, now initialize all the relevant values */
	if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
		err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);
		kfree(scn);
		up(&scn_mutex);
		return NULL;
	}
	dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf);

	if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
		err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);
		kfree(scn->obuf);
		kfree(scn);
		up(&scn_mutex);
		return NULL;
	}
	dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
	

	switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
	case 0x04b8:		/* Seiko/Epson */
		scn->rd_nak_timeout = HZ * 40;
		break;
	case 0x055f:		/* Mustek */
	case 0x0400:		/* Another Mustek */
	case 0x0ff5:		/* And yet another Mustek */
		scn->rd_nak_timeout = HZ * 1;
	default:
		scn->rd_nak_timeout = RD_NAK_TIMEOUT;
	}


	if (read_timeout > 0) {	/* User specified read timeout overrides everything */
		info("probe_scanner: User specified USB read timeout - %d", read_timeout);
		scn->rd_nak_timeout = read_timeout;
	}


	scn->bulk_in_ep = have_bulk_in;
	scn->bulk_out_ep = have_bulk_out;
	scn->intr_ep = have_intr;
	scn->present = 1;
	scn->scn_dev = dev;
	scn->scn_minor = scn_minor;
	scn->isopen = 0;

	sprintf(name, "scanner%d", scn->scn_minor);
	
	scn->devfs = devfs_register(usb_devfs_handle, name,
				    DEVFS_FL_DEFAULT, USB_MAJOR,
				    SCN_BASE_MNR + scn->scn_minor,
				    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
				    S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
	if (scn->devfs == NULL)
		dbg("scanner%d: device node registration failed", scn_minor);

	p_scn_table[scn_minor] = scn;

	up(&scn_mutex);

	return scn;
}

static void
disconnect_scanner(struct usb_device *dev, void *ptr)
{
	struct scn_usb_data *scn = (struct scn_usb_data *) ptr;

	down (&scn_mutex);
	down (&(scn->sem));

	if(scn->intr_ep) {
		dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
		usb_unlink_urb(scn->scn_irq);
	}
        usb_driver_release_interface(&scanner_driver,
                &scn->scn_dev->actconfig->interface[scn->ifnum]);

	kfree(scn->ibuf);
	kfree(scn->obuf);

	dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
	devfs_unregister(scn->devfs);
	usb_deregister_dev(&scanner_driver, 1, scn->scn_minor);
	p_scn_table[scn->scn_minor] = NULL;
	usb_free_urb(scn->scn_irq);
	up (&(scn->sem));
	kfree (scn);
	up (&scn_mutex);
}

static struct
usb_driver scanner_driver = {
	name:		"usbscanner",
	probe:		probe_scanner,
	disconnect:	disconnect_scanner,
	fops:		&usb_scanner_fops,
	minor:		SCN_BASE_MNR,
	num_minors:	SCN_MAX_MNR,
	id_table:	NULL, /* This would be scanner_device_ids, but we
				 need to check every USB device, in case
				 we match a user defined vendor/product ID. */
};

void __exit
usb_scanner_exit(void)
{
	usb_deregister(&scanner_driver);
}

int __init
usb_scanner_init (void)
{
        if (usb_register(&scanner_driver) < 0)
                return -1;

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

module_init(usb_scanner_init);
module_exit(usb_scanner_exit);

⌨️ 快捷键说明

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