xref: /linux/drivers/media/usb/gspca/stv0680.c (revision c942fddf8793b2013be8c901b47d0a8dc02bf99f)
1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
221f1b932SHans de Goede /*
321f1b932SHans de Goede  * STV0680 USB Camera Driver
421f1b932SHans de Goede  *
51fddcf0eSHans de Goede  * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com>
621f1b932SHans de Goede  *
721f1b932SHans de Goede  * This module is adapted from the in kernel v4l1 stv680 driver:
821f1b932SHans de Goede  *
921f1b932SHans de Goede  *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
1021f1b932SHans de Goede  *
1121f1b932SHans de Goede  * Thanks to STMicroelectronics for information on the usb commands, and
1221f1b932SHans de Goede  * to Steve Miller at STM for his help and encouragement while I was
1321f1b932SHans de Goede  * writing this driver.
1421f1b932SHans de Goede  */
1521f1b932SHans de Goede 
16133a9fe9SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17133a9fe9SJoe Perches 
1821f1b932SHans de Goede #define MODULE_NAME "stv0680"
1921f1b932SHans de Goede 
2021f1b932SHans de Goede #include "gspca.h"
2121f1b932SHans de Goede 
221fddcf0eSHans de Goede MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
2321f1b932SHans de Goede MODULE_DESCRIPTION("STV0680 USB Camera Driver");
2421f1b932SHans de Goede MODULE_LICENSE("GPL");
2521f1b932SHans de Goede 
2621f1b932SHans de Goede /* specific webcam descriptor */
2721f1b932SHans de Goede struct sd {
2821f1b932SHans de Goede 	struct gspca_dev gspca_dev;		/* !! must be the first item */
2921f1b932SHans de Goede 	struct v4l2_pix_format mode;
3021f1b932SHans de Goede 	u8 orig_mode;
3121f1b932SHans de Goede 	u8 video_mode;
3221f1b932SHans de Goede 	u8 current_mode;
3321f1b932SHans de Goede };
3421f1b932SHans de Goede 
3521f1b932SHans de Goede static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,
3621f1b932SHans de Goede 		       int size)
3721f1b932SHans de Goede {
3821f1b932SHans de Goede 	int ret = -1;
3921f1b932SHans de Goede 	u8 req_type = 0;
40388a6d54SHans de Goede 	unsigned int pipe = 0;
4121f1b932SHans de Goede 
4221f1b932SHans de Goede 	switch (set) {
4321f1b932SHans de Goede 	case 0: /*  0xc1  */
4421f1b932SHans de Goede 		req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
45388a6d54SHans de Goede 		pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);
4621f1b932SHans de Goede 		break;
4721f1b932SHans de Goede 	case 1: /*  0x41  */
4821f1b932SHans de Goede 		req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
49388a6d54SHans de Goede 		pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
5021f1b932SHans de Goede 		break;
5121f1b932SHans de Goede 	case 2:	/*  0x80  */
5221f1b932SHans de Goede 		req_type = USB_DIR_IN | USB_RECIP_DEVICE;
53388a6d54SHans de Goede 		pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);
5421f1b932SHans de Goede 		break;
5521f1b932SHans de Goede 	case 3:	/*  0x40  */
5621f1b932SHans de Goede 		req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
57388a6d54SHans de Goede 		pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
5821f1b932SHans de Goede 		break;
5921f1b932SHans de Goede 	}
6021f1b932SHans de Goede 
61388a6d54SHans de Goede 	ret = usb_control_msg(gspca_dev->dev, pipe,
6221f1b932SHans de Goede 			      req, req_type,
6321f1b932SHans de Goede 			      val, 0, gspca_dev->usb_buf, size, 500);
6421f1b932SHans de Goede 
6521f1b932SHans de Goede 	if ((ret < 0) && (req != 0x0a))
66133a9fe9SJoe Perches 		pr_err("usb_control_msg error %i, request = 0x%x, error = %i\n",
6721f1b932SHans de Goede 		       set, req, ret);
6821f1b932SHans de Goede 
6921f1b932SHans de Goede 	return ret;
7021f1b932SHans de Goede }
7121f1b932SHans de Goede 
7221f1b932SHans de Goede static int stv0680_handle_error(struct gspca_dev *gspca_dev, int ret)
7321f1b932SHans de Goede {
7421f1b932SHans de Goede 	stv_sndctrl(gspca_dev, 0, 0x80, 0, 0x02); /* Get Last Error */
7552173c5fSJoe Perches 	gspca_err(gspca_dev, "last error: %i,  command = 0x%x\n",
7621f1b932SHans de Goede 		  gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
7721f1b932SHans de Goede 	return ret;
7821f1b932SHans de Goede }
7921f1b932SHans de Goede 
8021f1b932SHans de Goede static int stv0680_get_video_mode(struct gspca_dev *gspca_dev)
8121f1b932SHans de Goede {
8221f1b932SHans de Goede 	/* Note not sure if this init of usb_buf is really necessary */
8321f1b932SHans de Goede 	memset(gspca_dev->usb_buf, 0, 8);
8421f1b932SHans de Goede 	gspca_dev->usb_buf[0] = 0x0f;
8521f1b932SHans de Goede 
8621f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 0, 0x87, 0, 0x08) != 0x08) {
8752173c5fSJoe Perches 		gspca_err(gspca_dev, "Get_Camera_Mode failed\n");
8821f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -EIO);
8921f1b932SHans de Goede 	}
9021f1b932SHans de Goede 
9121f1b932SHans de Goede 	return gspca_dev->usb_buf[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */
9221f1b932SHans de Goede }
9321f1b932SHans de Goede 
9421f1b932SHans de Goede static int stv0680_set_video_mode(struct gspca_dev *gspca_dev, u8 mode)
9521f1b932SHans de Goede {
9621f1b932SHans de Goede 	struct sd *sd = (struct sd *) gspca_dev;
9721f1b932SHans de Goede 
9821f1b932SHans de Goede 	if (sd->current_mode == mode)
9921f1b932SHans de Goede 		return 0;
10021f1b932SHans de Goede 
10121f1b932SHans de Goede 	memset(gspca_dev->usb_buf, 0, 8);
10221f1b932SHans de Goede 	gspca_dev->usb_buf[0] = mode;
10321f1b932SHans de Goede 
10421f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 3, 0x07, 0x0100, 0x08) != 0x08) {
10552173c5fSJoe Perches 		gspca_err(gspca_dev, "Set_Camera_Mode failed\n");
10621f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -EIO);
10721f1b932SHans de Goede 	}
10821f1b932SHans de Goede 
10921f1b932SHans de Goede 	/* Verify we got what we've asked for */
11021f1b932SHans de Goede 	if (stv0680_get_video_mode(gspca_dev) != mode) {
11152173c5fSJoe Perches 		gspca_err(gspca_dev, "Error setting camera video mode!\n");
11221f1b932SHans de Goede 		return -EIO;
11321f1b932SHans de Goede 	}
11421f1b932SHans de Goede 
11521f1b932SHans de Goede 	sd->current_mode = mode;
11621f1b932SHans de Goede 
11721f1b932SHans de Goede 	return 0;
11821f1b932SHans de Goede }
11921f1b932SHans de Goede 
12021f1b932SHans de Goede /* this function is called at probe time */
12121f1b932SHans de Goede static int sd_config(struct gspca_dev *gspca_dev,
12221f1b932SHans de Goede 			const struct usb_device_id *id)
12321f1b932SHans de Goede {
12421f1b932SHans de Goede 	int ret;
12521f1b932SHans de Goede 	struct sd *sd = (struct sd *) gspca_dev;
12621f1b932SHans de Goede 	struct cam *cam = &gspca_dev->cam;
12721f1b932SHans de Goede 
128f58c91ceSJonathan McCrohan 	/* Give the camera some time to settle, otherwise initialization will
129ab269d30SHans de Goede 	   fail on hotplug, and yes it really needs a full second. */
130ab269d30SHans de Goede 	msleep(1000);
131ab269d30SHans de Goede 
13221f1b932SHans de Goede 	/* ping camera to be sure STV0680 is present */
13321f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 0, 0x88, 0x5678, 0x02) != 0x02 ||
13421f1b932SHans de Goede 	    gspca_dev->usb_buf[0] != 0x56 || gspca_dev->usb_buf[1] != 0x78) {
13552173c5fSJoe Perches 		gspca_err(gspca_dev, "STV(e): camera ping failed!!\n");
13621f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -ENODEV);
13721f1b932SHans de Goede 	}
13821f1b932SHans de Goede 
13921f1b932SHans de Goede 	/* get camera descriptor */
14021f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x09) != 0x09)
14121f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -ENODEV);
14221f1b932SHans de Goede 
14321f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x22) != 0x22 ||
14421f1b932SHans de Goede 	    gspca_dev->usb_buf[7] != 0xa0 || gspca_dev->usb_buf[8] != 0x23) {
14552173c5fSJoe Perches 		gspca_err(gspca_dev, "Could not get descriptor 0200\n");
14621f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -ENODEV);
14721f1b932SHans de Goede 	}
14821f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 0, 0x8a, 0, 0x02) != 0x02)
14921f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -ENODEV);
15021f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 0, 0x8b, 0, 0x24) != 0x24)
15121f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -ENODEV);
15221f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10)
15321f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -ENODEV);
15421f1b932SHans de Goede 
15521f1b932SHans de Goede 	if (!(gspca_dev->usb_buf[7] & 0x09)) {
15652173c5fSJoe Perches 		gspca_err(gspca_dev, "Camera supports neither CIF nor QVGA mode\n");
15721f1b932SHans de Goede 		return -ENODEV;
15821f1b932SHans de Goede 	}
15921f1b932SHans de Goede 	if (gspca_dev->usb_buf[7] & 0x01)
16037d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "Camera supports CIF mode\n");
16121f1b932SHans de Goede 	if (gspca_dev->usb_buf[7] & 0x02)
16237d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "Camera supports VGA mode\n");
163388a6d54SHans de Goede 	if (gspca_dev->usb_buf[7] & 0x04)
16437d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "Camera supports QCIF mode\n");
16521f1b932SHans de Goede 	if (gspca_dev->usb_buf[7] & 0x08)
16637d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "Camera supports QVGA mode\n");
16721f1b932SHans de Goede 
16821f1b932SHans de Goede 	if (gspca_dev->usb_buf[7] & 0x01)
16921f1b932SHans de Goede 		sd->video_mode = 0x00; /* CIF */
17021f1b932SHans de Goede 	else
17121f1b932SHans de Goede 		sd->video_mode = 0x03; /* QVGA */
17221f1b932SHans de Goede 
17321f1b932SHans de Goede 	/* FW rev, ASIC rev, sensor ID  */
17437d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_PROBE, "Firmware rev is %i.%i\n",
17521f1b932SHans de Goede 		  gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
17637d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_PROBE, "ASIC rev is %i.%i",
17721f1b932SHans de Goede 		  gspca_dev->usb_buf[2], gspca_dev->usb_buf[3]);
17837d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_PROBE, "Sensor ID is %i",
17921f1b932SHans de Goede 		  (gspca_dev->usb_buf[4]*16) + (gspca_dev->usb_buf[5]>>4));
18021f1b932SHans de Goede 
18121f1b932SHans de Goede 
18221f1b932SHans de Goede 	ret = stv0680_get_video_mode(gspca_dev);
18321f1b932SHans de Goede 	if (ret < 0)
18421f1b932SHans de Goede 		return ret;
18521f1b932SHans de Goede 	sd->current_mode = sd->orig_mode = ret;
18621f1b932SHans de Goede 
18721f1b932SHans de Goede 	ret = stv0680_set_video_mode(gspca_dev, sd->video_mode);
18821f1b932SHans de Goede 	if (ret < 0)
18921f1b932SHans de Goede 		return ret;
19021f1b932SHans de Goede 
19121f1b932SHans de Goede 	/* Get mode details */
19221f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 0, 0x8f, 0, 0x10) != 0x10)
19321f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -EIO);
19421f1b932SHans de Goede 
19521f1b932SHans de Goede 	cam->bulk = 1;
19621f1b932SHans de Goede 	cam->bulk_nurbs = 1; /* The cam cannot handle more */
19721f1b932SHans de Goede 	cam->bulk_size = (gspca_dev->usb_buf[0] << 24) |
19821f1b932SHans de Goede 			 (gspca_dev->usb_buf[1] << 16) |
19921f1b932SHans de Goede 			 (gspca_dev->usb_buf[2] << 8) |
20021f1b932SHans de Goede 			 (gspca_dev->usb_buf[3]);
20121f1b932SHans de Goede 	sd->mode.width = (gspca_dev->usb_buf[4] << 8) |
20221f1b932SHans de Goede 			 (gspca_dev->usb_buf[5]);  /* 322, 356, 644 */
20321f1b932SHans de Goede 	sd->mode.height = (gspca_dev->usb_buf[6] << 8) |
20421f1b932SHans de Goede 			  (gspca_dev->usb_buf[7]); /* 242, 292, 484 */
20521f1b932SHans de Goede 	sd->mode.pixelformat = V4L2_PIX_FMT_STV0680;
20621f1b932SHans de Goede 	sd->mode.field = V4L2_FIELD_NONE;
20721f1b932SHans de Goede 	sd->mode.bytesperline = sd->mode.width;
20821f1b932SHans de Goede 	sd->mode.sizeimage = cam->bulk_size;
20921f1b932SHans de Goede 	sd->mode.colorspace = V4L2_COLORSPACE_SRGB;
21021f1b932SHans de Goede 
21121f1b932SHans de Goede 	/* origGain = gspca_dev->usb_buf[12]; */
21221f1b932SHans de Goede 
21321f1b932SHans de Goede 	cam->cam_mode = &sd->mode;
21421f1b932SHans de Goede 	cam->nmodes = 1;
21521f1b932SHans de Goede 
21621f1b932SHans de Goede 
21721f1b932SHans de Goede 	ret = stv0680_set_video_mode(gspca_dev, sd->orig_mode);
21821f1b932SHans de Goede 	if (ret < 0)
21921f1b932SHans de Goede 		return ret;
22021f1b932SHans de Goede 
22121f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 ||
22221f1b932SHans de Goede 	    gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) {
223133a9fe9SJoe Perches 		pr_err("Could not get descriptor 0100\n");
22421f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -EIO);
22521f1b932SHans de Goede 	}
22621f1b932SHans de Goede 
22721f1b932SHans de Goede 	return 0;
22821f1b932SHans de Goede }
22921f1b932SHans de Goede 
23021f1b932SHans de Goede /* this function is called at probe and resume time */
23121f1b932SHans de Goede static int sd_init(struct gspca_dev *gspca_dev)
23221f1b932SHans de Goede {
23321f1b932SHans de Goede 	return 0;
23421f1b932SHans de Goede }
23521f1b932SHans de Goede 
23621f1b932SHans de Goede /* -- start the camera -- */
23721f1b932SHans de Goede static int sd_start(struct gspca_dev *gspca_dev)
23821f1b932SHans de Goede {
23921f1b932SHans de Goede 	int ret;
24021f1b932SHans de Goede 	struct sd *sd = (struct sd *) gspca_dev;
24121f1b932SHans de Goede 
24221f1b932SHans de Goede 	ret = stv0680_set_video_mode(gspca_dev, sd->video_mode);
24321f1b932SHans de Goede 	if (ret < 0)
24421f1b932SHans de Goede 		return ret;
24521f1b932SHans de Goede 
24621f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10)
24721f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -EIO);
24821f1b932SHans de Goede 
24921f1b932SHans de Goede 	/* Start stream at:
25021f1b932SHans de Goede 	   0x0000 = CIF (352x288)
25121f1b932SHans de Goede 	   0x0100 = VGA (640x480)
25221f1b932SHans de Goede 	   0x0300 = QVGA (320x240) */
25321f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 1, 0x09, sd->video_mode << 8, 0x0) != 0x0)
25421f1b932SHans de Goede 		return stv0680_handle_error(gspca_dev, -EIO);
25521f1b932SHans de Goede 
25621f1b932SHans de Goede 	return 0;
25721f1b932SHans de Goede }
25821f1b932SHans de Goede 
25921f1b932SHans de Goede static void sd_stopN(struct gspca_dev *gspca_dev)
26021f1b932SHans de Goede {
26121f1b932SHans de Goede 	/* This is a high priority command; it stops all lower order cmds */
26221f1b932SHans de Goede 	if (stv_sndctrl(gspca_dev, 1, 0x04, 0x0000, 0x0) != 0x0)
26321f1b932SHans de Goede 		stv0680_handle_error(gspca_dev, -EIO);
26421f1b932SHans de Goede }
26521f1b932SHans de Goede 
26621f1b932SHans de Goede static void sd_stop0(struct gspca_dev *gspca_dev)
26721f1b932SHans de Goede {
26821f1b932SHans de Goede 	struct sd *sd = (struct sd *) gspca_dev;
26921f1b932SHans de Goede 
27021f1b932SHans de Goede 	if (!sd->gspca_dev.present)
27121f1b932SHans de Goede 		return;
27221f1b932SHans de Goede 
27321f1b932SHans de Goede 	stv0680_set_video_mode(gspca_dev, sd->orig_mode);
27421f1b932SHans de Goede }
27521f1b932SHans de Goede 
27621f1b932SHans de Goede static void sd_pkt_scan(struct gspca_dev *gspca_dev,
27776dd272bSJean-Francois Moine 			u8 *data,
27821f1b932SHans de Goede 			int len)
27921f1b932SHans de Goede {
28021f1b932SHans de Goede 	struct sd *sd = (struct sd *) gspca_dev;
28121f1b932SHans de Goede 
28221f1b932SHans de Goede 	/* Every now and then the camera sends a 16 byte packet, no idea
28321f1b932SHans de Goede 	   what it contains, but it is not image data, when this
28421f1b932SHans de Goede 	   happens the frame received before this packet is corrupt,
28521f1b932SHans de Goede 	   so discard it. */
28621f1b932SHans de Goede 	if (len != sd->mode.sizeimage) {
28721f1b932SHans de Goede 		gspca_dev->last_packet_type = DISCARD_PACKET;
28821f1b932SHans de Goede 		return;
28921f1b932SHans de Goede 	}
29021f1b932SHans de Goede 
29121f1b932SHans de Goede 	/* Finish the previous frame, we do this upon reception of the next
29221f1b932SHans de Goede 	   packet, even though it is already complete so that the strange 16
29321f1b932SHans de Goede 	   byte packets send after a corrupt frame can discard it. */
29476dd272bSJean-Francois Moine 	gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
29521f1b932SHans de Goede 
29621f1b932SHans de Goede 	/* Store the just received frame */
29776dd272bSJean-Francois Moine 	gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
29821f1b932SHans de Goede }
29921f1b932SHans de Goede 
30021f1b932SHans de Goede /* sub-driver description */
30121f1b932SHans de Goede static const struct sd_desc sd_desc = {
30221f1b932SHans de Goede 	.name = MODULE_NAME,
30321f1b932SHans de Goede 	.config = sd_config,
30421f1b932SHans de Goede 	.init = sd_init,
30521f1b932SHans de Goede 	.start = sd_start,
30621f1b932SHans de Goede 	.stopN = sd_stopN,
30721f1b932SHans de Goede 	.stop0 = sd_stop0,
30821f1b932SHans de Goede 	.pkt_scan = sd_pkt_scan,
30921f1b932SHans de Goede };
31021f1b932SHans de Goede 
31121f1b932SHans de Goede /* -- module initialisation -- */
31295c967c1SJean-François Moine static const struct usb_device_id device_table[] = {
31321f1b932SHans de Goede 	{USB_DEVICE(0x0553, 0x0202)},
31421f1b932SHans de Goede 	{USB_DEVICE(0x041e, 0x4007)},
31521f1b932SHans de Goede 	{}
31621f1b932SHans de Goede };
31721f1b932SHans de Goede MODULE_DEVICE_TABLE(usb, device_table);
31821f1b932SHans de Goede 
31921f1b932SHans de Goede /* -- device connect -- */
32021f1b932SHans de Goede static int sd_probe(struct usb_interface *intf,
32121f1b932SHans de Goede 			const struct usb_device_id *id)
32221f1b932SHans de Goede {
32321f1b932SHans de Goede 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
32421f1b932SHans de Goede 				THIS_MODULE);
32521f1b932SHans de Goede }
32621f1b932SHans de Goede 
32721f1b932SHans de Goede static struct usb_driver sd_driver = {
32821f1b932SHans de Goede 	.name = MODULE_NAME,
32921f1b932SHans de Goede 	.id_table = device_table,
33021f1b932SHans de Goede 	.probe = sd_probe,
33121f1b932SHans de Goede 	.disconnect = gspca_disconnect,
33221f1b932SHans de Goede #ifdef CONFIG_PM
33321f1b932SHans de Goede 	.suspend = gspca_suspend,
33421f1b932SHans de Goede 	.resume = gspca_resume,
3358bb58964SHans de Goede 	.reset_resume = gspca_resume,
33621f1b932SHans de Goede #endif
33721f1b932SHans de Goede };
33821f1b932SHans de Goede 
339ecb3b2b3SGreg Kroah-Hartman module_usb_driver(sd_driver);
340