if ((rc = kernel_thread(fsg_main_thread, fsg, (CLONE_VM | CLONE_FS | CLONE_FILES))) < 0) goto out; fsg->thread_pid = rc; 
fsg->thread_task = kthread_create(fsg_main_thread, fsg, "file-storage-gadget"); if (IS_ERR(fsg->thread_task)) { rc = PTR_ERR(fsg->thread_task); goto out; } 
static int __init fsg_bind(struct usb_gadget *gadget){	struct fsg_dev		*fsg = the_fsg;	int			rc;	int			i;	struct lun		*curlun;	struct usb_ep		*ep;	struct usb_request	*req;	char			*pathbuf, *p;	fsg->gadget = gadget;	set_gadget_data(gadget, fsg);	fsg->ep0 = gadget->ep0;	fsg->ep0->driver_data = fsg;	if ((rc = check_parameters(fsg)) != 0)		goto out;	if (mod_data.removable) {	// Enable the store_xxx attributes		dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644;		dev_attr_ro.store = store_ro;		dev_attr_file.store = store_file;	}	/* Find out how many LUNs there should be */	i = mod_data.nluns;	if (i == 0)		i = max(mod_data.num_filenames, 1);	if (i > MAX_LUNS) {		ERROR(fsg, "invalid number of LUNs: %d\n", i);		rc = -EINVAL;		goto out;	}	/* Create the LUNs, open their backing files, and register the	 * LUN devices in sysfs. */	fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL);	if (!fsg->luns) {		rc = -ENOMEM;		goto out;	}	memset(fsg->luns, 0, i * sizeof(struct lun));	fsg->nluns = i;	for (i = 0; i < fsg->nluns; ++i) {		curlun = &fsg->luns[i];		curlun->ro = ro[i];		curlun->dev.parent = &gadget->dev;		curlun->dev.driver = &fsg_driver.driver;		dev_set_drvdata(&curlun->dev, fsg);		snprintf(curlun->dev.bus_id, BUS_ID_SIZE,				"%s-lun%d", gadget->dev.bus_id, i);		if ((rc = device_register(&curlun->dev)) != 0)			INFO(fsg, "failed to register LUN%d: %d\n", i, rc);		else {			curlun->registered = 1;			curlun->dev.release = lun_release;			device_create_file(&curlun->dev, &dev_attr_ro);			device_create_file(&curlun->dev, &dev_attr_file);		}		if (file[i] && *file[i]) {			if ((rc = open_backing_file(curlun, file[i])) != 0)				goto out;		} else if (!mod_data.removable) {			ERROR(fsg, "no file given for LUN%d\n", i);			rc = -EINVAL;			goto out;		}	}	/* Find all the endpoints we will use */	usb_ep_autoconfig_reset(gadget);	ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc);	if (!ep)		goto autoconf_fail;	ep->driver_data = fsg;		// claim the endpoint	fsg->bulk_in = ep;	ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc);	if (!ep)		goto autoconf_fail;	ep->driver_data = fsg;		// claim the endpoint	fsg->bulk_out = ep;	if (transport_is_cbi()) {		ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc);		if (!ep)			goto autoconf_fail;		ep->driver_data = fsg;		// claim the endpoint		fsg->intr_in = ep;	}	/* Fix up the descriptors */	device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;	device_desc.idVendor = cpu_to_le16(mod_data.vendor);	device_desc.idProduct = cpu_to_le16(mod_data.product);	device_desc.bcdDevice = cpu_to_le16(mod_data.release);	i = (transport_is_cbi() ? 3 : 2);	// Number of endpoints	intf_desc.bNumEndpoints = i;	intf_desc.bInterfaceSubClass = mod_data.protocol_type;	intf_desc.bInterfaceProtocol = mod_data.transport_type;	fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;#ifdef CONFIG_USB_GADGET_DUALSPEED	hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;	/* Assume ep0 uses the same maxpacket value for both speeds */	dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;	/* Assume that all endpoint addresses are the same for both speeds */	hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;	hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;	hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;#endif	if (gadget->is_otg) {		otg_desc.bmAttributes |= USB_OTG_HNP,		config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;	}	rc = -ENOMEM;	/* Allocate the request and buffer for endpoint 0 */	fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);	if (!req)		goto out;	req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE,			&req->dma, GFP_KERNEL);	if (!req->buf)		goto out;	req->complete = ep0_complete;	/* Allocate the data buffers */	for (i = 0; i < NUM_BUFFERS; ++i) {		struct fsg_buffhd	*bh = &fsg->buffhds[i];		bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen,				&bh->dma, GFP_KERNEL);		if (!bh->buf)			goto out;		bh->next = bh + 1;	}	fsg->buffhds[NUM_BUFFERS - 1].next = &fsg->buffhds[0];	/* This should reflect the actual gadget power source */	usb_gadget_set_selfpowered(gadget);	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",			system_utsname.sysname, system_utsname.release,			gadget->name);	/* On a real device, serial[] would be loaded from permanent	 * storage.  We just encode it from the driver version string. */	for (i = 0; i < sizeof(serial) - 2; i += 2) {		unsigned char		c = DRIVER_VERSION[i / 2];		if (!c)			break;		sprintf(&serial[i], "%02X", c);	}	if ((rc = kernel_thread(fsg_main_thread, fsg, (CLONE_VM | CLONE_FS |			CLONE_FILES))) < 0)		goto out;	fsg->thread_pid = rc;	INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");	INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);	for (i = 0; i < fsg->nluns; ++i) {		curlun = &fsg->luns[i];		if (backing_file_is_open(curlun)) {			p = NULL;			if (pathbuf) {				p = d_path(curlun->filp->f_dentry,					curlun->filp->f_vfsmnt,					pathbuf, PATH_MAX);				if (IS_ERR(p))					p = NULL;			}			LINFO(curlun, "ro=%d, file: %s\n",					curlun->ro, (p ? p : "(error)"));		}	}	kfree(pathbuf);	DBG(fsg, "transport=%s (x%02x)\n",			mod_data.transport_name, mod_data.transport_type);	DBG(fsg, "protocol=%s (x%02x)\n",			mod_data.protocol_name, mod_data.protocol_type);	DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",			mod_data.vendor, mod_data.product, mod_data.release);	DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",			mod_data.removable, mod_data.can_stall,			mod_data.buflen);	DBG(fsg, "I/O thread pid: %d\n", fsg->thread_pid);	return 0;autoconf_fail:	ERROR(fsg, "unable to autoconfigure all endpoints\n");	rc = -ENOTSUPP;out:	fsg->state = FSG_STATE_TERMINATED;	// The thread is dead	fsg_unbind(gadget);	close_all_backing_files(fsg);	return rc;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/22efcf4adec4262e0f49e6225f6cd070e4a85d20/file_storage.c/clean/drivers/usb/gadget/file_storage.c