xref: /linux/drivers/media/usb/gspca/vicam.c (revision 0ea8a56de21be24cb79abb03dee79aabcd60a316)
1fd9871f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
249b61ec9SHans de Goede /*
349b61ec9SHans de Goede  * gspca ViCam subdriver
449b61ec9SHans de Goede  *
549b61ec9SHans de Goede  * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com>
649b61ec9SHans de Goede  *
749b61ec9SHans de Goede  * Based on the usbvideo vicam driver, which is:
849b61ec9SHans de Goede  *
949b61ec9SHans de Goede  * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
10ccb7cc00SChris Cheney  *                    Chris Cheney (chris.cheney@gmail.com),
1149b61ec9SHans de Goede  *                    Pavel Machek (pavel@ucw.cz),
1249b61ec9SHans de Goede  *                    John Tyner (jtyner@cs.ucr.edu),
1349b61ec9SHans de Goede  *                    Monroe Williams (monroe@pobox.com)
1449b61ec9SHans de Goede  */
1549b61ec9SHans de Goede 
16133a9fe9SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17133a9fe9SJoe Perches 
1849b61ec9SHans de Goede #define MODULE_NAME "vicam"
1949b61ec9SHans de Goede #define HEADER_SIZE 64
2049b61ec9SHans de Goede 
2149b61ec9SHans de Goede #include <linux/workqueue.h>
2249b61ec9SHans de Goede #include <linux/slab.h>
2349b61ec9SHans de Goede #include <linux/firmware.h>
2449b61ec9SHans de Goede #include <linux/ihex.h>
2549b61ec9SHans de Goede #include "gspca.h"
2649b61ec9SHans de Goede 
27d74185b4STim Gardner #define VICAM_FIRMWARE "vicam/firmware.fw"
28d74185b4STim Gardner 
2949b61ec9SHans de Goede MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
3049b61ec9SHans de Goede MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver");
3149b61ec9SHans de Goede MODULE_LICENSE("GPL");
32d74185b4STim Gardner MODULE_FIRMWARE(VICAM_FIRMWARE);
3349b61ec9SHans de Goede 
3449b61ec9SHans de Goede struct sd {
3549b61ec9SHans de Goede 	struct gspca_dev gspca_dev;	/* !! must be the first item */
3649b61ec9SHans de Goede 	struct work_struct work_struct;
3749b61ec9SHans de Goede };
3849b61ec9SHans de Goede 
3949b61ec9SHans de Goede /* The vicam sensor has a resolution of 512 x 244, with I believe square
4049b61ec9SHans de Goede    pixels, but this is forced to a 4:3 ratio by optics. So it has
4149b61ec9SHans de Goede    non square pixels :( */
4249b61ec9SHans de Goede static struct v4l2_pix_format vicam_mode[] = {
4349b61ec9SHans de Goede 	{ 256, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
4449b61ec9SHans de Goede 		.bytesperline = 256,
4549b61ec9SHans de Goede 		.sizeimage = 256 * 122,
4649b61ec9SHans de Goede 		.colorspace = V4L2_COLORSPACE_SRGB,},
4749b61ec9SHans de Goede 	/* 2 modes with somewhat more square pixels */
4849b61ec9SHans de Goede 	{ 256, 200, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
4949b61ec9SHans de Goede 		.bytesperline = 256,
5049b61ec9SHans de Goede 		.sizeimage = 256 * 200,
5149b61ec9SHans de Goede 		.colorspace = V4L2_COLORSPACE_SRGB,},
5249b61ec9SHans de Goede 	{ 256, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
5349b61ec9SHans de Goede 		.bytesperline = 256,
5449b61ec9SHans de Goede 		.sizeimage = 256 * 240,
5549b61ec9SHans de Goede 		.colorspace = V4L2_COLORSPACE_SRGB,},
5649b61ec9SHans de Goede #if 0   /* This mode has extremely non square pixels, testing use only */
5749b61ec9SHans de Goede 	{ 512, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
5849b61ec9SHans de Goede 		.bytesperline = 512,
5949b61ec9SHans de Goede 		.sizeimage = 512 * 122,
6049b61ec9SHans de Goede 		.colorspace = V4L2_COLORSPACE_SRGB,},
6149b61ec9SHans de Goede #endif
6249b61ec9SHans de Goede 	{ 512, 244, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
6349b61ec9SHans de Goede 		.bytesperline = 512,
6449b61ec9SHans de Goede 		.sizeimage = 512 * 244,
6549b61ec9SHans de Goede 		.colorspace = V4L2_COLORSPACE_SRGB,},
6649b61ec9SHans de Goede };
6749b61ec9SHans de Goede 
6849b61ec9SHans de Goede static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request,
6949b61ec9SHans de Goede 	u16 value, u16 index, u8 *data, u16 len)
7049b61ec9SHans de Goede {
7149b61ec9SHans de Goede 	int ret;
7249b61ec9SHans de Goede 
7349b61ec9SHans de Goede 	ret = usb_control_msg(gspca_dev->dev,
7449b61ec9SHans de Goede 			      usb_sndctrlpipe(gspca_dev->dev, 0),
7549b61ec9SHans de Goede 			      request,
7649b61ec9SHans de Goede 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
7749b61ec9SHans de Goede 			      value, index, data, len, 1000);
7849b61ec9SHans de Goede 	if (ret < 0)
79133a9fe9SJoe Perches 		pr_err("control msg req %02X error %d\n", request, ret);
8049b61ec9SHans de Goede 
8149b61ec9SHans de Goede 	return ret;
8249b61ec9SHans de Goede }
8349b61ec9SHans de Goede 
8449b61ec9SHans de Goede static int vicam_set_camera_power(struct gspca_dev *gspca_dev, int state)
8549b61ec9SHans de Goede {
8649b61ec9SHans de Goede 	int ret;
8749b61ec9SHans de Goede 
8849b61ec9SHans de Goede 	ret = vicam_control_msg(gspca_dev, 0x50, state, 0, NULL, 0);
8949b61ec9SHans de Goede 	if (ret < 0)
9049b61ec9SHans de Goede 		return ret;
9149b61ec9SHans de Goede 
9249b61ec9SHans de Goede 	if (state)
9349b61ec9SHans de Goede 		ret = vicam_control_msg(gspca_dev, 0x55, 1, 0, NULL, 0);
9449b61ec9SHans de Goede 
9549b61ec9SHans de Goede 	return ret;
9649b61ec9SHans de Goede }
9749b61ec9SHans de Goede 
9849b61ec9SHans de Goede /*
99844db450SHans de Goede  *  request and read a block of data
10049b61ec9SHans de Goede  */
10149b61ec9SHans de Goede static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size)
10249b61ec9SHans de Goede {
10349b61ec9SHans de Goede 	int ret, unscaled_height, act_len = 0;
10449b61ec9SHans de Goede 	u8 *req_data = gspca_dev->usb_buf;
1054910adf1SHans Verkuil 	s32 expo = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
1064910adf1SHans Verkuil 	s32 gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
10749b61ec9SHans de Goede 
10849b61ec9SHans de Goede 	memset(req_data, 0, 16);
1094910adf1SHans Verkuil 	req_data[0] = gain;
1101966bc2aSOndrej Zary 	if (gspca_dev->pixfmt.width == 256)
11149b61ec9SHans de Goede 		req_data[1] |= 0x01; /* low nibble x-scale */
1121966bc2aSOndrej Zary 	if (gspca_dev->pixfmt.height <= 122) {
11349b61ec9SHans de Goede 		req_data[1] |= 0x10; /* high nibble y-scale */
1141966bc2aSOndrej Zary 		unscaled_height = gspca_dev->pixfmt.height * 2;
11549b61ec9SHans de Goede 	} else
1161966bc2aSOndrej Zary 		unscaled_height = gspca_dev->pixfmt.height;
11749b61ec9SHans de Goede 	req_data[2] = 0x90; /* unknown, does not seem to do anything */
11849b61ec9SHans de Goede 	if (unscaled_height <= 200)
11949b61ec9SHans de Goede 		req_data[3] = 0x06; /* vend? */
12049b61ec9SHans de Goede 	else if (unscaled_height <= 242) /* Yes 242 not 240 */
12149b61ec9SHans de Goede 		req_data[3] = 0x07; /* vend? */
12249b61ec9SHans de Goede 	else /* Up to 244 lines with req_data[3] == 0x08 */
12349b61ec9SHans de Goede 		req_data[3] = 0x08; /* vend? */
12449b61ec9SHans de Goede 
1254910adf1SHans Verkuil 	if (expo < 256) {
12649b61ec9SHans de Goede 		/* Frame rate maxed out, use partial frame expo time */
1274910adf1SHans Verkuil 		req_data[4] = 255 - expo;
12849b61ec9SHans de Goede 		req_data[5] = 0x00;
12949b61ec9SHans de Goede 		req_data[6] = 0x00;
13049b61ec9SHans de Goede 		req_data[7] = 0x01;
13149b61ec9SHans de Goede 	} else {
13249b61ec9SHans de Goede 		/* Modify frame rate */
13349b61ec9SHans de Goede 		req_data[4] = 0x00;
13449b61ec9SHans de Goede 		req_data[5] = 0x00;
1354910adf1SHans Verkuil 		req_data[6] = expo & 0xFF;
1364910adf1SHans Verkuil 		req_data[7] = expo >> 8;
13749b61ec9SHans de Goede 	}
13849b61ec9SHans de Goede 	req_data[8] = ((244 - unscaled_height) / 2) & ~0x01; /* vstart */
13949b61ec9SHans de Goede 	/* bytes 9-15 do not seem to affect exposure or image quality */
14049b61ec9SHans de Goede 
14149b61ec9SHans de Goede 	mutex_lock(&gspca_dev->usb_lock);
14249b61ec9SHans de Goede 	ret = vicam_control_msg(gspca_dev, 0x51, 0x80, 0, req_data, 16);
14349b61ec9SHans de Goede 	mutex_unlock(&gspca_dev->usb_lock);
14449b61ec9SHans de Goede 	if (ret < 0)
14549b61ec9SHans de Goede 		return ret;
14649b61ec9SHans de Goede 
14749b61ec9SHans de Goede 	ret = usb_bulk_msg(gspca_dev->dev,
14849b61ec9SHans de Goede 			   usb_rcvbulkpipe(gspca_dev->dev, 0x81),
14949b61ec9SHans de Goede 			   data, size, &act_len, 10000);
15049b61ec9SHans de Goede 	/* successful, it returns 0, otherwise  negative */
15149b61ec9SHans de Goede 	if (ret < 0 || act_len != size) {
152133a9fe9SJoe Perches 		pr_err("bulk read fail (%d) len %d/%d\n",
15349b61ec9SHans de Goede 		       ret, act_len, size);
15449b61ec9SHans de Goede 		return -EIO;
15549b61ec9SHans de Goede 	}
15649b61ec9SHans de Goede 	return 0;
15749b61ec9SHans de Goede }
15849b61ec9SHans de Goede 
159844db450SHans de Goede /*
160844db450SHans de Goede  * This function is called as a workqueue function and runs whenever the camera
16149b61ec9SHans de Goede  * is streaming data. Because it is a workqueue function it is allowed to sleep
16249b61ec9SHans de Goede  * so we can use synchronous USB calls. To avoid possible collisions with other
163844db450SHans de Goede  * threads attempting to use gspca_dev->usb_buf we take the usb_lock when
164844db450SHans de Goede  * performing USB operations using it. In practice we don't really need this
165844db450SHans de Goede  * as the cameras controls are only written from the workqueue.
16649b61ec9SHans de Goede  */
16749b61ec9SHans de Goede static void vicam_dostream(struct work_struct *work)
16849b61ec9SHans de Goede {
16949b61ec9SHans de Goede 	struct sd *sd = container_of(work, struct sd, work_struct);
17049b61ec9SHans de Goede 	struct gspca_dev *gspca_dev = &sd->gspca_dev;
17149b61ec9SHans de Goede 	int ret, frame_sz;
17249b61ec9SHans de Goede 	u8 *buffer;
17349b61ec9SHans de Goede 
17449b61ec9SHans de Goede 	frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage +
17549b61ec9SHans de Goede 		   HEADER_SIZE;
1765334b342SHans de Goede 	buffer = kmalloc(frame_sz, GFP_KERNEL);
17749b61ec9SHans de Goede 	if (!buffer) {
178133a9fe9SJoe Perches 		pr_err("Couldn't allocate USB buffer\n");
17949b61ec9SHans de Goede 		goto exit;
18049b61ec9SHans de Goede 	}
18149b61ec9SHans de Goede 
182345321dcSHans de Goede 	while (gspca_dev->present && gspca_dev->streaming) {
1834ad34da0SHans Verkuil #ifdef CONFIG_PM
1844ad34da0SHans Verkuil 		if (gspca_dev->frozen)
1854ad34da0SHans Verkuil 			break;
1864ad34da0SHans Verkuil #endif
18749b61ec9SHans de Goede 		ret = vicam_read_frame(gspca_dev, buffer, frame_sz);
18849b61ec9SHans de Goede 		if (ret < 0)
18949b61ec9SHans de Goede 			break;
19049b61ec9SHans de Goede 
19149b61ec9SHans de Goede 		/* Note the frame header contents seem to be completely
19249b61ec9SHans de Goede 		   constant, they do not change with either image, or
19349b61ec9SHans de Goede 		   settings. So we simply discard it. The frames have
19449b61ec9SHans de Goede 		   a very similar 64 byte footer, which we don't even
19549b61ec9SHans de Goede 		   bother reading from the cam */
19649b61ec9SHans de Goede 		gspca_frame_add(gspca_dev, FIRST_PACKET,
19749b61ec9SHans de Goede 				buffer + HEADER_SIZE,
19849b61ec9SHans de Goede 				frame_sz - HEADER_SIZE);
19949b61ec9SHans de Goede 		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
20049b61ec9SHans de Goede 	}
20149b61ec9SHans de Goede exit:
20249b61ec9SHans de Goede 	kfree(buffer);
20349b61ec9SHans de Goede }
20449b61ec9SHans de Goede 
20549b61ec9SHans de Goede /* This function is called at probe time just before sd_init */
20649b61ec9SHans de Goede static int sd_config(struct gspca_dev *gspca_dev,
20749b61ec9SHans de Goede 		const struct usb_device_id *id)
20849b61ec9SHans de Goede {
20949b61ec9SHans de Goede 	struct cam *cam = &gspca_dev->cam;
21049b61ec9SHans de Goede 	struct sd *sd = (struct sd *)gspca_dev;
21149b61ec9SHans de Goede 
21249b61ec9SHans de Goede 	/* We don't use the buffer gspca allocates so make it small. */
21349b61ec9SHans de Goede 	cam->bulk = 1;
21449b61ec9SHans de Goede 	cam->bulk_size = 64;
21549b61ec9SHans de Goede 	cam->cam_mode = vicam_mode;
21649b61ec9SHans de Goede 	cam->nmodes = ARRAY_SIZE(vicam_mode);
21749b61ec9SHans de Goede 
21849b61ec9SHans de Goede 	INIT_WORK(&sd->work_struct, vicam_dostream);
21949b61ec9SHans de Goede 
22049b61ec9SHans de Goede 	return 0;
22149b61ec9SHans de Goede }
22249b61ec9SHans de Goede 
22349b61ec9SHans de Goede /* this function is called at probe and resume time */
22449b61ec9SHans de Goede static int sd_init(struct gspca_dev *gspca_dev)
22549b61ec9SHans de Goede {
22649b61ec9SHans de Goede 	int ret;
22749b61ec9SHans de Goede 	const struct ihex_binrec *rec;
228*3f649ab7SKees Cook 	const struct firmware *fw;
22949b61ec9SHans de Goede 	u8 *firmware_buf;
23049b61ec9SHans de Goede 
231d74185b4STim Gardner 	ret = request_ihex_firmware(&fw, VICAM_FIRMWARE,
23249b61ec9SHans de Goede 				    &gspca_dev->dev->dev);
23349b61ec9SHans de Goede 	if (ret) {
234133a9fe9SJoe Perches 		pr_err("Failed to load \"vicam/firmware.fw\": %d\n", ret);
23549b61ec9SHans de Goede 		return ret;
23649b61ec9SHans de Goede 	}
23749b61ec9SHans de Goede 
23849b61ec9SHans de Goede 	firmware_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
23949b61ec9SHans de Goede 	if (!firmware_buf) {
24049b61ec9SHans de Goede 		ret = -ENOMEM;
24149b61ec9SHans de Goede 		goto exit;
24249b61ec9SHans de Goede 	}
24349b61ec9SHans de Goede 	for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {
24449b61ec9SHans de Goede 		memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len));
24549b61ec9SHans de Goede 		ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf,
24649b61ec9SHans de Goede 					be16_to_cpu(rec->len));
24749b61ec9SHans de Goede 		if (ret < 0)
24849b61ec9SHans de Goede 			break;
24949b61ec9SHans de Goede 	}
25049b61ec9SHans de Goede 
25149b61ec9SHans de Goede 	kfree(firmware_buf);
25249b61ec9SHans de Goede exit:
25349b61ec9SHans de Goede 	release_firmware(fw);
25449b61ec9SHans de Goede 	return ret;
25549b61ec9SHans de Goede }
25649b61ec9SHans de Goede 
25749b61ec9SHans de Goede /* Set up for getting frames. */
25849b61ec9SHans de Goede static int sd_start(struct gspca_dev *gspca_dev)
25949b61ec9SHans de Goede {
26049b61ec9SHans de Goede 	struct sd *sd = (struct sd *)gspca_dev;
26149b61ec9SHans de Goede 	int ret;
26249b61ec9SHans de Goede 
26349b61ec9SHans de Goede 	ret = vicam_set_camera_power(gspca_dev, 1);
26449b61ec9SHans de Goede 	if (ret < 0)
26549b61ec9SHans de Goede 		return ret;
26649b61ec9SHans de Goede 
26795705083SBhaktipriya Shridhar 	schedule_work(&sd->work_struct);
26849b61ec9SHans de Goede 
26949b61ec9SHans de Goede 	return 0;
27049b61ec9SHans de Goede }
27149b61ec9SHans de Goede 
27249b61ec9SHans de Goede /* called on streamoff with alt==0 and on disconnect */
27349b61ec9SHans de Goede /* the usb_lock is held at entry - restore on exit */
27449b61ec9SHans de Goede static void sd_stop0(struct gspca_dev *gspca_dev)
27549b61ec9SHans de Goede {
27649b61ec9SHans de Goede 	struct sd *dev = (struct sd *)gspca_dev;
27749b61ec9SHans de Goede 
27849b61ec9SHans de Goede 	/* wait for the work queue to terminate */
27949b61ec9SHans de Goede 	mutex_unlock(&gspca_dev->usb_lock);
28049b61ec9SHans de Goede 	/* This waits for vicam_dostream to finish */
28195705083SBhaktipriya Shridhar 	flush_work(&dev->work_struct);
28249b61ec9SHans de Goede 	mutex_lock(&gspca_dev->usb_lock);
28349b61ec9SHans de Goede 
284345321dcSHans de Goede 	if (gspca_dev->present)
28549b61ec9SHans de Goede 		vicam_set_camera_power(gspca_dev, 0);
28649b61ec9SHans de Goede }
28749b61ec9SHans de Goede 
2884910adf1SHans Verkuil static int sd_init_controls(struct gspca_dev *gspca_dev)
2894910adf1SHans Verkuil {
2904910adf1SHans Verkuil 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
2914910adf1SHans Verkuil 
2924910adf1SHans Verkuil 	gspca_dev->vdev.ctrl_handler = hdl;
2934910adf1SHans Verkuil 	v4l2_ctrl_handler_init(hdl, 2);
2944910adf1SHans Verkuil 	gspca_dev->exposure = v4l2_ctrl_new_std(hdl, NULL,
2954910adf1SHans Verkuil 			V4L2_CID_EXPOSURE, 0, 2047, 1, 256);
2964910adf1SHans Verkuil 	gspca_dev->gain = v4l2_ctrl_new_std(hdl, NULL,
2974910adf1SHans Verkuil 			V4L2_CID_GAIN, 0, 255, 1, 200);
2984910adf1SHans Verkuil 
2994910adf1SHans Verkuil 	if (hdl->error) {
3004910adf1SHans Verkuil 		pr_err("Could not initialize controls\n");
3014910adf1SHans Verkuil 		return hdl->error;
3024910adf1SHans Verkuil 	}
3034910adf1SHans Verkuil 	return 0;
3044910adf1SHans Verkuil }
3054910adf1SHans Verkuil 
30649b61ec9SHans de Goede /* Table of supported USB devices */
30749b61ec9SHans de Goede static const struct usb_device_id device_table[] = {
30849b61ec9SHans de Goede 	{USB_DEVICE(0x04c1, 0x009d)},
30949b61ec9SHans de Goede 	{USB_DEVICE(0x0602, 0x1001)},
31049b61ec9SHans de Goede 	{}
31149b61ec9SHans de Goede };
31249b61ec9SHans de Goede 
31349b61ec9SHans de Goede MODULE_DEVICE_TABLE(usb, device_table);
31449b61ec9SHans de Goede 
31549b61ec9SHans de Goede /* sub-driver description */
31649b61ec9SHans de Goede static const struct sd_desc sd_desc = {
31749b61ec9SHans de Goede 	.name   = MODULE_NAME,
31849b61ec9SHans de Goede 	.config = sd_config,
31949b61ec9SHans de Goede 	.init   = sd_init,
3204910adf1SHans Verkuil 	.init_controls = sd_init_controls,
32149b61ec9SHans de Goede 	.start  = sd_start,
32249b61ec9SHans de Goede 	.stop0  = sd_stop0,
32349b61ec9SHans de Goede };
32449b61ec9SHans de Goede 
32549b61ec9SHans de Goede /* -- device connect -- */
32649b61ec9SHans de Goede static int sd_probe(struct usb_interface *intf,
32749b61ec9SHans de Goede 		const struct usb_device_id *id)
32849b61ec9SHans de Goede {
32949b61ec9SHans de Goede 	return gspca_dev_probe(intf, id,
33049b61ec9SHans de Goede 			&sd_desc,
33149b61ec9SHans de Goede 			sizeof(struct sd),
33249b61ec9SHans de Goede 			THIS_MODULE);
33349b61ec9SHans de Goede }
33449b61ec9SHans de Goede 
33549b61ec9SHans de Goede static struct usb_driver sd_driver = {
33649b61ec9SHans de Goede 	.name       = MODULE_NAME,
33749b61ec9SHans de Goede 	.id_table   = device_table,
33849b61ec9SHans de Goede 	.probe      = sd_probe,
33949b61ec9SHans de Goede 	.disconnect = gspca_disconnect,
34049b61ec9SHans de Goede #ifdef CONFIG_PM
34149b61ec9SHans de Goede 	.suspend = gspca_suspend,
34249b61ec9SHans de Goede 	.resume  = gspca_resume,
3438bb58964SHans de Goede 	.reset_resume = gspca_resume,
34449b61ec9SHans de Goede #endif
34549b61ec9SHans de Goede };
34649b61ec9SHans de Goede 
347ecb3b2b3SGreg Kroah-Hartman module_usb_driver(sd_driver);
348