Exemplo n.º 1
0
static void rts51x_disconnect(struct usb_interface *intf)
{
	struct rts51x_chip *chip = (struct rts51x_chip *)usb_get_intfdata(intf);

	RTS51X_DEBUGP("rts51x_disconnect() called\n");
	quiesce_and_remove_host(chip);
	release_everything(chip);
}
void our_disconnect(struct usb_interface *intf){
struct us_data *us = usb_get_intfdata(intf);
//---------------------------
pr_info("23 disconnect\n");
	US_DEBUGP("storage_disconnect() called\n");
	quiesce_and_remove_host(us);
	release_everything(us);
}
Exemplo n.º 3
0
static void rtsx_remove(struct pci_dev *pci)
{
	struct rtsx_dev *dev = pci_get_drvdata(pci);

	dev_info(&pci->dev, "rtsx_remove() called\n");

	quiesce_and_remove_host(dev);
	release_everything(dev);
}
Exemplo n.º 4
0
static void __devexit rtsx_remove(struct pci_dev *pci)
{
	struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci);

	printk(KERN_INFO "rtsx_remove() called\n");

	quiesce_and_remove_host(dev);
	release_everything(dev);

	pci_set_drvdata(pci, NULL);
}
Exemplo n.º 5
0
static int rtsx_probe(struct pci_dev *pci,
				const struct pci_device_id *pci_id)
{
	struct Scsi_Host *host;
	struct rtsx_dev *dev;
	int err = 0;
	struct task_struct *th;

	dev_dbg(&pci->dev, "Realtek PCI-E card reader detected\n");

	err = pcim_enable_device(pci);
	if (err < 0) {
		dev_err(&pci->dev, "PCI enable device failed!\n");
		return err;
	}

	err = pci_request_regions(pci, CR_DRIVER_NAME);
	if (err < 0) {
		dev_err(&pci->dev, "PCI request regions for %s failed!\n",
			CR_DRIVER_NAME);
		return err;
	}

	/*
	 * Ask the SCSI layer to allocate a host structure, with extra
	 * space at the end for our private rtsx_dev structure.
	 */
	host = scsi_host_alloc(&rtsx_host_template, sizeof(*dev));
	if (!host) {
		dev_err(&pci->dev, "Unable to allocate the scsi host\n");
		return -ENOMEM;
	}

	dev = host_to_rtsx(host);
	memset(dev, 0, sizeof(struct rtsx_dev));

	dev->chip = kzalloc(sizeof(struct rtsx_chip), GFP_KERNEL);
	if (!dev->chip) {
		err = -ENOMEM;
		goto errout;
	}

	spin_lock_init(&dev->reg_lock);
	mutex_init(&(dev->dev_mutex));
	init_completion(&dev->cmnd_ready);
	init_completion(&dev->control_exit);
	init_completion(&dev->polling_exit);
	init_completion(&(dev->notify));
	init_completion(&dev->scanning_done);
	init_waitqueue_head(&dev->delay_wait);

	dev->pci = pci;
	dev->irq = -1;

	dev_info(&pci->dev, "Resource length: 0x%x\n",
		 (unsigned int)pci_resource_len(pci, 0));
	dev->addr = pci_resource_start(pci, 0);
	dev->remap_addr = ioremap_nocache(dev->addr, pci_resource_len(pci, 0));
	if (!dev->remap_addr) {
		dev_err(&pci->dev, "ioremap error\n");
		err = -ENXIO;
		goto errout;
	}

	/*
	 * Using "unsigned long" cast here to eliminate gcc warning in
	 * 64-bit system
	 */
	dev_info(&pci->dev, "Original address: 0x%lx, remapped address: 0x%lx\n",
		 (unsigned long)(dev->addr), (unsigned long)(dev->remap_addr));

	dev->rtsx_resv_buf = dmam_alloc_coherent(&pci->dev, RTSX_RESV_BUF_LEN,
			&dev->rtsx_resv_buf_addr, GFP_KERNEL);
	if (!dev->rtsx_resv_buf) {
		dev_err(&pci->dev, "alloc dma buffer fail\n");
		err = -ENXIO;
		goto errout;
	}
	dev->chip->host_cmds_ptr = dev->rtsx_resv_buf;
	dev->chip->host_cmds_addr = dev->rtsx_resv_buf_addr;
	dev->chip->host_sg_tbl_ptr = dev->rtsx_resv_buf + HOST_CMDS_BUF_LEN;
	dev->chip->host_sg_tbl_addr = dev->rtsx_resv_buf_addr +
				      HOST_CMDS_BUF_LEN;

	dev->chip->rtsx = dev;

	rtsx_init_options(dev->chip);

	dev_info(&pci->dev, "pci->irq = %d\n", pci->irq);

	if (dev->chip->msi_en) {
		if (pci_enable_msi(pci) < 0)
			dev->chip->msi_en = 0;
	}

	if (rtsx_acquire_irq(dev) < 0) {
		err = -EBUSY;
		goto errout;
	}

	pci_set_master(pci);
	synchronize_irq(dev->irq);

	rtsx_init_chip(dev->chip);

	/*
	 * set the supported max_lun and max_id for the scsi host
	 * NOTE: the minimal value of max_id is 1
	 */
	host->max_id = 1;
	host->max_lun = dev->chip->max_lun;

	/* Start up our control thread */
	th = kthread_run(rtsx_control_thread, dev, CR_DRIVER_NAME);
	if (IS_ERR(th)) {
		dev_err(&pci->dev, "Unable to start control thread\n");
		err = PTR_ERR(th);
		goto errout;
	}
	dev->ctl_thread = th;

	err = scsi_add_host(host, &pci->dev);
	if (err) {
		dev_err(&pci->dev, "Unable to add the scsi host\n");
		goto errout;
	}

	/* Start up the thread for delayed SCSI-device scanning */
	th = kthread_run(rtsx_scan_thread, dev, "rtsx-scan");
	if (IS_ERR(th)) {
		dev_err(&pci->dev, "Unable to start the device-scanning thread\n");
		complete(&dev->scanning_done);
		quiesce_and_remove_host(dev);
		err = PTR_ERR(th);
		goto errout;
	}

	/* Start up the thread for polling thread */
	th = kthread_run(rtsx_polling_thread, dev, "rtsx-polling");
	if (IS_ERR(th)) {
		dev_err(&pci->dev, "Unable to start the device-polling thread\n");
		quiesce_and_remove_host(dev);
		err = PTR_ERR(th);
		goto errout;
	}
	dev->polling_thread = th;

	pci_set_drvdata(pci, dev);

	return 0;

	/* We come here if there are any problems */
errout:
	dev_err(&pci->dev, "rtsx_probe() failed\n");
	release_everything(dev);

	return err;
}
Exemplo n.º 6
0
int main(int argc, char **argv)
{
	int input_fd;
	int output_fd;
	int fft_dev_fd;
	int result;
	IN_SAMPLE_TYPE *in_buf;
	OUT_SAMPLE_TYPE *out_buf;
	
	initialize_everything(argc, argv);
	
	/* allocate storage for input, output and config buffers */
	in_buf = (IN_SAMPLE_TYPE*) NE10_MALLOC (FFT_POINTS * sizeof(IN_SAMPLE_TYPE));
	if(in_buf == NULL)
		error(1, errno, "in_buf allocation");
		
	out_buf = (OUT_SAMPLE_TYPE*) NE10_MALLOC (FFT_POINTS * sizeof(OUT_SAMPLE_TYPE));
	if(out_buf == NULL)
		error(1, errno, "out_buf allocation");
		
	/* open the input and output files and fft dev */
	input_fd = open(g_input_filename, O_RDONLY);
	if(input_fd < 0)
		error(1, errno, "opening input file '%s'", g_input_filename);
	
	output_fd = open(g_output_filename, O_WRONLY | O_CREAT);
	if(output_fd < 0)
		error(1, errno, "opening output file '%s'", g_output_filename);

	fft_dev_fd = open("/dev/fft", O_RDWR);
	if(fft_dev_fd < 0)
		error(1, errno, "opening fft_dev_fd");

	/* capture the start value of the GT */
	g_start_time = get_gt_value();
	
	/* read the input data */
	result = read(input_fd, in_buf, FFT_POINTS * sizeof(IN_SAMPLE_TYPE));
	if(result < 0)
		error(1, errno, "read input file");
	if(result != (FFT_POINTS * sizeof(IN_SAMPLE_TYPE)))
		error(1, 0, "input data size, expected %d but got %d", FFT_POINTS * sizeof(IN_SAMPLE_TYPE), result);
	
	/* perform FFT with FPGA hardware, 16 bit input 24/32 bit output */
	result = write(fft_dev_fd, in_buf, FFT_POINTS * sizeof(IN_SAMPLE_TYPE));
	if(result < 0)
		error(1, errno, "write to fft_dev_fd");
	if (result != (int)(FFT_POINTS * sizeof(IN_SAMPLE_TYPE)))
		error(1, 0, "fft_dev_fd input data size, expected %d but got %d", FFT_POINTS * sizeof(IN_SAMPLE_TYPE), result);
	
	result = read(fft_dev_fd, out_buf, FFT_POINTS * sizeof(OUT_SAMPLE_TYPE));
	if(result < 0)
		error(1, errno, "read from fft_dev_fd");
	if (result != (int)(FFT_POINTS * sizeof(OUT_SAMPLE_TYPE)))
		error(1, 0, "fft_dev_fd output data size, expected %d but got %d", FFT_POINTS * sizeof(OUT_SAMPLE_TYPE), result);
	
	/* write the output data */
	result = write(output_fd, out_buf, FFT_POINTS * sizeof(OUT_SAMPLE_TYPE));
	if(result < 0)
		error(1, errno, "write output file");
	if(result != (FFT_POINTS * sizeof(OUT_SAMPLE_TYPE)))
		error(1, 0, "output data size, expected %d but got %d", FFT_POINTS * sizeof(OUT_SAMPLE_TYPE), result);

	/* capture the end value of the GT */
	g_end_time = get_gt_value();

	/* close the input and output files and fft dev */
	close(fft_dev_fd);
	close(output_fd);
	close(input_fd);

	/* free storage for input, output and config buffers */
	NE10_FREE (out_buf);
	NE10_FREE (in_buf);
	
	print_results();
	release_everything();
	return 0;
}
//probe书中有教
static int our_probe(struct usb_interface *intf,
			 const struct usb_device_id *id){
struct us_data *us;
int result;
//device
struct device *dev;
//scsihost
struct Scsi_Host *host;
//检测id是否符合 和intf
struct us_unusual_dev *unusual_dev;

unusual_dev=(id - usb_storage_usb_ids) + us_unusual_dev_list;
if(usb_usual_check_type(id,USB_US_TYPE_STOR) || usb_usual_ignore_device(intf))
return -ENXIO;

printk(KERN_ALERT "probe usb   usb  detected!\n");
//分配个host

host = scsi_host_alloc(&usb_stor_host_template,sizeof(*us));
if(!host){
dev_warn(&intf->dev,"fail to allocate the scsi host\n");
return -ENOMEM;
}
//host中的一些初始化
host->max_cmd_len = 16;
host-> sg_tablesize = usb_stor_sg_tablesize(intf);
us= host_to_us(host);//us 作为host中 的us
//分内存?
memset(us,0,sizeof(struct us_data));
mutex_init(&(us->dev_mutex));
init_completion(&us->cmnd_ready);
init_completion(&(us->notify));
init_waitqueue_head(&us->delay_wait);
INIT_DELAYED_WORK(&us->scan_dwork,usb_stor_scan_dwork);

result = associate_dev(us,intf);
if(result)
         goto Bad;
result = get_device_info(us,id,unusual_dev);
if(result)
         goto Bad;
//transport protocol
get_transport(us);
get_protocol(us);

if(!us->transport ||!us->proto_handler){
result=-ENXIO;
goto Bad;
}
printk(KERN_ALERT"Transport: %s\n",us->transport_name);
printk(KERN_ALERT"Protocol: %s\n",us->transport_name);
dev = &us->pusb_intf->dev;
//设置max lun
if(us->fflags & US_FL_SINGLE_LUN)
us->max_lun =0;

//endpoint get pipe
result = get_pipes(us);
if(result)
goto Bad;
//如果u盘前十个指令错误,重置
if (us->fflags & US_FL_INITIAL_READ10)
		set_bit(US_FLIDX_REDO_READ10, &us->dflags);
//申请子资源,添加进host
result=usb_stor_acquire_sesources(us);
if(result)
goto Bad;
snprintf(us->scsi_name,sizeof(us->scsi_name),"our-usb-storage%s",dev_name(&us->pusb_intf->dev));
result= scsi_add_host(us_to_host(us),dev);
if(result){
printk(KERN_ALERT"UNable to add the host\n");
goto Bad;
}
//scsi设备延时探测
usb_autopm_get_interface_no_resume(us->pusb_intf);
set_bit(US_FLIDX_SCAN_PENDING,&us->dflags);
if(delay_use>0)
          dev_dbg(dev,"waiting for device before scanning\n");
queue_delayed_work(system_freezable_wq,&us->scan_dwork,delay_use * HZ);


return 0;
Bad:

 printk(KERN_ALERT "probe false!\n");
release_everything(us);
return result;
   }
Exemplo n.º 8
0
int main(int argc, char **argv)
{
	int input_fd;
	int output_fd;
	int result;
	IN_SAMPLE_TYPE *in_buf;
	OUT_SAMPLE_TYPE *out_buf;
	CFG_TYPE cfg;
	int i;
	
	initialize_everything(argc, argv);
	
	/* allocate storage for input, output and config buffers */
	in_buf = (IN_SAMPLE_TYPE*) NE10_MALLOC (FFT_POINTS * sizeof(IN_SAMPLE_TYPE));
	if(in_buf == NULL)
		error(1, errno, "in_buf allocation");
		
	out_buf = (OUT_SAMPLE_TYPE*) NE10_MALLOC (FFT_POINTS * sizeof(OUT_SAMPLE_TYPE));
	if(out_buf == NULL)
		error(1, errno, "out_buf allocation");
		
	cfg = CFG_ALLOC_FUNC(FFT_CALC_POINTS);
	if(cfg == NULL)
		error(1, errno, "cfg allocation");

	/* open the input and output files */
	input_fd = open(g_input_filename, O_RDONLY);
	if(input_fd < 0)
		error(1, errno, "opening input file '%s'", g_input_filename);
	
	output_fd = open(g_output_filename, O_WRONLY | O_CREAT);
	if(output_fd < 0)
		error(1, errno, "opening output file '%s'", g_output_filename);

	/* capture the start value of the GT */
	g_start_time = get_gt_value();
	
	/* read the input data */
	result = read(input_fd, in_buf, FFT_POINTS * sizeof(IN_SAMPLE_TYPE));
	if(result < 0)
		error(1, errno, "read input file");
	if(result != (FFT_POINTS * sizeof(IN_SAMPLE_TYPE)))
		error(1, 0, "input data size, expected %d but got %d", FFT_POINTS * sizeof(IN_SAMPLE_TYPE), result);

	/* compute FFT */
	for (i = 0; i < FFT_CALC_ROUNDS ; i++) {
		FFT_FUNC(out_buf + (i * FFT_CALC_POINTS), in_buf + (i * FFT_CALC_POINTS), cfg, 0, 1);
	}
	
	/* write the output data */
	result = write(output_fd, out_buf, FFT_POINTS * sizeof(OUT_SAMPLE_TYPE));
	if(result < 0)
		error(1, errno, "write output file");
	if(result != (FFT_POINTS * sizeof(OUT_SAMPLE_TYPE)))
		error(1, 0, "output data size, expected %d but got %d", FFT_POINTS * sizeof(OUT_SAMPLE_TYPE), result);

	/* capture the end value of the GT */
	g_end_time = get_gt_value();

	/* close the input and output files */
	close(output_fd);
	close(input_fd);

	/* free storage for input, output and config buffers */
	NE10_FREE (cfg);
	NE10_FREE (out_buf);
	NE10_FREE (in_buf);
	
	print_results();
	release_everything();
	return 0;
}
int main(int argc, char **argv)
{
	int input_fd;
	int output_fd;
	int raw256stream_dev_fd;
	int result;
	IN_SAMPLE_TYPE *in_buf;
	int j;
	
	initialize_everything(argc, argv);
	
	/* allocate storage for input */
	in_buf = (IN_SAMPLE_TYPE*) NE10_MALLOC (FFT_POINTS * sizeof(IN_SAMPLE_TYPE));
	if(in_buf == NULL)
		error(1, errno, "in_buf allocation");
		
	/* open the input and output files and raw256stream device */
	input_fd = open(g_input_filename, O_RDONLY);
	if(input_fd < 0)
		error(1, errno, "opening input file '%s'", g_input_filename);
	
	output_fd = open(g_output_filename, O_WRONLY | O_CREAT);
	if(output_fd < 0)
		error(1, errno, "opening output file '%s'", g_output_filename);

	raw256stream_dev_fd = open("/dev/raw256stream", O_RDWR);
	if(raw256stream_dev_fd < 0)
		error(1, errno, "opening raw256stream_dev_fd");

	/* read the input data */
	result = read(input_fd, in_buf, FFT_CALC_POINTS * sizeof(IN_SAMPLE_TYPE));
	if(result < 0)
		error(1, errno, "read input file");
	if(result != (FFT_CALC_POINTS * sizeof(IN_SAMPLE_TYPE)))
		error(1, 0, "input data size, expected %d but got %d", FFT_CALC_POINTS * sizeof(IN_SAMPLE_TYPE), result);
	
	/* write the waveform buffer */
	result = write(raw256stream_dev_fd, in_buf, FFT_CALC_POINTS * sizeof(IN_SAMPLE_TYPE));
	if(result < 0)
		error(1, errno, "write waveform buffer");
	if(result != (FFT_CALC_POINTS * sizeof(IN_SAMPLE_TYPE)))
		error(1, 0, "output data size, expected %d but got %d", FFT_CALC_POINTS * sizeof(IN_SAMPLE_TYPE), result);
	
	/* capture the start value of the GT */
	g_start_time = get_gt_value();
	
	for(j = 0 ; j < FFT_IN_ROUNDS ; j++) {
		/* read the input stream */
		result = read(raw256stream_dev_fd, in_buf, FFT_POINTS * sizeof(IN_SAMPLE_TYPE));
		if(result < 0)
			error(1, errno, "read input stream");
		if(result != (FFT_POINTS * sizeof(IN_SAMPLE_TYPE)))
			error(1, 0, "input data size, expected %d but got %d", FFT_POINTS * sizeof(IN_SAMPLE_TYPE), result);

		/* write the output data */
		result = write(output_fd, in_buf, FFT_POINTS * sizeof(IN_SAMPLE_TYPE));
		if(result < 0)
			error(1, errno, "write output file");
		if(result != (FFT_POINTS * sizeof(IN_SAMPLE_TYPE)))
			error(1, 0, "output data size, expected %d but got %d", FFT_POINTS * sizeof(IN_SAMPLE_TYPE), result);
	}
	
	/* capture the end value of the GT */
	g_end_time = get_gt_value();

	/* close the input and output files and stream device */
	close(raw256stream_dev_fd);
	close(output_fd);
	close(input_fd);
	
	/* free storage for input, output and config buffers */
	NE10_FREE (in_buf);
	
	print_results();
	release_everything();
	return 0;
}
Exemplo n.º 10
0
static int rtsx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
{
	struct Scsi_Host *host;
	struct rtsx_dev *dev;
	int err = 0;
	struct task_struct *th;

	printk(KERN_INFO "--- %s ---\n", DRIVER_MAKE_TIME);

	err = pci_enable_device(pci);
	if (err < 0) {
		printk(KERN_ERR "PCI enable device failed!\n");
		return err;
	}

	err = pci_request_regions(pci, CR_DRIVER_NAME);
	if (err < 0) {
		printk(KERN_ERR "PCI request regions for %s failed!\n", CR_DRIVER_NAME);
		pci_disable_device(pci);
		return err;
	}

	/*
	 * Ask the SCSI layer to allocate a host structure, with extra
	 * space at the end for our private rtsx_dev structure.
	 */
	host = scsi_host_alloc(&rtsx_host_template, sizeof(*dev));
	if (!host) {
		printk(KERN_ERR "Unable to allocate the scsi host\n");
		pci_release_regions(pci);
		pci_disable_device(pci);
		return -ENOMEM;
	}

	dev = host_to_rtsx(host);
	memset(dev, 0, sizeof(struct rtsx_dev));

	dev->chip = (struct rtsx_chip *)kmalloc(sizeof(struct rtsx_chip), GFP_KERNEL);
	if (dev->chip == NULL) {
		goto errout;
	}
	memset(dev->chip, 0, sizeof(struct rtsx_chip));

	spin_lock_init(&dev->reg_lock);
	mutex_init(&(dev->dev_mutex));
	sema_init(&(dev->sema), 0);
	init_completion(&(dev->notify));
	init_waitqueue_head(&dev->delay_wait);

	dev->pci = pci;
	dev->irq = -1;

	printk(KERN_INFO "Resource length: 0x%x\n", (unsigned int)pci_resource_len(pci,0));
	dev->addr = pci_resource_start(pci, 0);
	dev->remap_addr = ioremap_nocache(dev->addr, pci_resource_len(pci,0));
	if (dev->remap_addr == NULL) {
		printk(KERN_ERR "ioremap error\n");
		err = -ENXIO;
		goto errout;
	}

	printk(KERN_INFO "Original address: 0x%lx, remapped address: 0x%lx\n", 
			(unsigned long)(dev->addr), (unsigned long)(dev->remap_addr));

	dev->rtsx_resv_buf = dma_alloc_coherent(&(pci->dev), RTSX_RESV_BUF_LEN, 
			&(dev->rtsx_resv_buf_addr), GFP_KERNEL);
	if (dev->rtsx_resv_buf == NULL) {
		printk(KERN_ERR "alloc dma buffer fail\n");
		err = -ENXIO;
		goto errout;
	}
	dev->chip->host_cmds_ptr = dev->rtsx_resv_buf;
	dev->chip->host_cmds_addr = dev->rtsx_resv_buf_addr;
	dev->chip->host_sg_tbl_ptr = dev->rtsx_resv_buf + HOST_CMDS_BUF_LEN;
	dev->chip->host_sg_tbl_addr = dev->rtsx_resv_buf_addr + HOST_CMDS_BUF_LEN;

	dev->chip->rtsx = dev;
	
	rtsx_init_options(dev->chip);

	printk(KERN_INFO "pci->irq = %d\n", pci->irq);
	
	if (dev->chip->msi_en) {
		if (pci_enable_msi(pci) < 0) {
			dev->chip->msi_en = 0;
		}
	}
	
	if (rtsx_acquire_irq(dev) < 0) {
		err = -EBUSY;
		goto errout;
	}

	pci_set_master(pci);
	synchronize_irq(dev->irq);

	err = scsi_add_host(host, &pci->dev);
	if (err) {
		printk(KERN_ERR "Unable to add the scsi host\n");
		goto errout;
	}

	rtsx_init_chip(dev->chip);
	
	
	th = kthread_create(rtsx_control_thread, dev, CR_DRIVER_NAME);
	if (IS_ERR(th)) {
		printk(KERN_ERR "Unable to start control thread\n");
		err = PTR_ERR(th);
		goto errout;
	}

	/* Take a reference to the host for the control thread and
	 * count it among all the threads we have launched.  Then
	 * start it up. */
	scsi_host_get(rtsx_to_host(dev));
	atomic_inc(&total_threads);
	wake_up_process(th);
	
	
	th = kthread_create(rtsx_scan_thread, dev, "rtsx-scan");
	if (IS_ERR(th)) {
		printk(KERN_ERR "Unable to start the device-scanning thread\n");
		quiesce_and_remove_host(dev);
		err = PTR_ERR(th);
		goto errout;
	}

	/* Take a reference to the host for the scanning thread and
	 * count it among all the threads we have launched.  Then
	 * start it up. */
	scsi_host_get(rtsx_to_host(dev));
	atomic_inc(&total_threads);
	wake_up_process(th);

	
	th = kthread_create(rtsx_polling_thread, dev, "rtsx-polling");
	if (IS_ERR(th)) {
		printk(KERN_ERR "Unable to start the device-polling thread\n");
		quiesce_and_remove_host(dev);
		err = PTR_ERR(th);
		goto errout;
	}

	/* Take a reference to the host for the polling thread and
	 * count it among all the threads we have launched.  Then
	 * start it up. */
	scsi_host_get(rtsx_to_host(dev));
	atomic_inc(&total_threads);
	wake_up_process(th);

	pci_set_drvdata(pci, dev);

	return 0;

	
errout:
	printk(KERN_ERR "rtsx_probe() failed\n");
	release_everything(dev);

	return err;
}
Exemplo n.º 11
0
static int rts51x_probe(struct usb_interface *intf,
			const struct usb_device_id *id)
{
	struct Scsi_Host *host;
	struct rts51x_chip *chip;
	struct rts51x_usb *rts51x;
	int result;
	struct task_struct *th;

	RTS51X_DEBUGP("%s detected\n", RTS51X_NAME);

	rts51x = kzalloc(sizeof(struct rts51x_usb), GFP_KERNEL);
	if (!rts51x) {
		printk(KERN_WARNING RTS51X_TIP
		       "Unable to allocate rts51x_usb\n");
		return -ENOMEM;
	}

	host = scsi_host_alloc(&rts51x_host_template, sizeof(*chip));
	if (!host) {
		printk(KERN_WARNING RTS51X_TIP
		       "Unable to allocate the scsi host\n");
		kfree(rts51x);
		return -ENOMEM;
	}

	host->max_cmd_len = 16;
	chip = host_to_rts51x(host);
	memset(chip, 0, sizeof(struct rts51x_chip));

	chip->vendor_id = id->idVendor;
	chip->product_id = id->idProduct;

	mutex_init(&(rts51x->dev_mutex));
	init_completion(&rts51x->cmnd_ready);
	init_completion(&rts51x->control_exit);
	init_completion(&rts51x->polling_exit);
	init_completion(&(rts51x->notify));
#ifdef SCSI_SCAN_DELAY
	init_waitqueue_head(&rts51x->delay_wait);
	init_completion(&rts51x->scanning_done);
#endif

	chip->usb = rts51x;

	
	result = associate_dev(chip, intf);
	if (result)
		goto BadDevice;

	
	result = get_pipes(chip);
	if (result)
		goto BadDevice;

	
	result = rts51x_acquire_resources(chip);
	if (result)
		goto BadDevice;

	
	th = kthread_run(rts51x_control_thread, chip, RTS51X_CTL_THREAD);
	if (IS_ERR(th)) {
		printk(KERN_WARNING RTS51X_TIP
		       "Unable to start control thread\n");
		result = PTR_ERR(th);
		goto BadDevice;
	}
	rts51x->ctl_thread = th;

	result = scsi_add_host(rts51x_to_host(chip), &rts51x->pusb_intf->dev);
	if (result) {
		printk(KERN_WARNING RTS51X_TIP "Unable to add the scsi host\n");
		goto BadDevice;
	}
#ifdef SCSI_SCAN_DELAY
	
	th = kthread_create(rts51x_scan_thread, chip, RTS51X_SCAN_THREAD);
	if (IS_ERR(th)) {
		printk(KERN_WARNING RTS51X_TIP
		       "Unable to start the device-scanning thread\n");
		complete(&rts51x->scanning_done);
		quiesce_and_remove_host(chip);
		result = PTR_ERR(th);
		goto BadDevice;
	}

	wake_up_process(th);
#else
	scsi_scan_host(rts51x_to_host(chip));
#endif

	
	th = kthread_run(rts51x_polling_thread, chip, RTS51X_POLLING_THREAD);
	if (IS_ERR(th)) {
		printk(KERN_WARNING RTS51X_TIP
		       "Unable to start polling thread\n");
		result = PTR_ERR(th);
		goto BadDevice;
	}
	rts51x->polling_thread = th;

#ifdef CONFIG_PM
	if (ss_en) {
		rts51x->pusb_intf->needs_remote_wakeup = needs_remote_wakeup;
		SET_PM_USAGE_CNT(chip, 1);
		RTS51X_DEBUGP("pm_usage_cnt = %d\n", GET_PM_USAGE_CNT(chip));
	}
#endif

	return 0;

	
BadDevice:
	RTS51X_DEBUGP("rts51x_probe() failed\n");
	release_everything(chip);
	return result;
}