From 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 21 Feb 2023 18:24:12 -0800 Subject: Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core: - Add dedicated kmem_cache for typical/small skb->head, avoid having to access struct page at kfree time, and improve memory use. - Introduce sysctl to set default RPS configuration for new netdevs. - Define Netlink protocol specification format which can be used to describe messages used by each family and auto-generate parsers. Add tools for generating kernel data structures and uAPI headers. - Expose all net/core sysctls inside netns. - Remove 4s sleep in netpoll if carrier is instantly detected on boot. - Add configurable limit of MDB entries per port, and port-vlan. - Continue populating drop reasons throughout the stack. - Retire a handful of legacy Qdiscs and classifiers. Protocols: - Support IPv4 big TCP (TSO frames larger than 64kB). - Add IP_LOCAL_PORT_RANGE socket option, to control local port range on socket by socket basis. - Track and report in procfs number of MPTCP sockets used. - Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path manager. - IPv6: don't check net.ipv6.route.max_size and rely on garbage collection to free memory (similarly to IPv4). - Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986). - ICMP: add per-rate limit counters. - Add support for user scanning requests in ieee802154. - Remove static WEP support. - Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate reporting. - WiFi 7 EHT channel puncturing support (client & AP). BPF: - Add a rbtree data structure following the "next-gen data structure" precedent set by recently added linked list, that is, by using kfunc + kptr instead of adding a new BPF map type. - Expose XDP hints via kfuncs with initial support for RX hash and timestamp metadata. - Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to better support decap on GRE tunnel devices not operating in collect metadata. - Improve x86 JIT's codegen for PROBE_MEM runtime error checks. - Remove the need for trace_printk_lock for bpf_trace_printk and bpf_trace_vprintk helpers. - Extend libbpf's bpf_tracing.h support for tracing arguments of kprobes/uprobes and syscall as a special case. - Significantly reduce the search time for module symbols by livepatch and BPF. - Enable cpumasks to be used as kptrs, which is useful for tracing programs tracking which tasks end up running on which CPUs in different time intervals. - Add support for BPF trampoline on s390x and riscv64. - Add capability to export the XDP features supported by the NIC. - Add __bpf_kfunc tag for marking kernel functions as kfuncs. - Add cgroup.memory=nobpf kernel parameter option to disable BPF memory accounting for container environments. Netfilter: - Remove the CLUSTERIP target. It has been marked as obsolete for years, and we still have WARN splats wrt races of the out-of-band /proc interface installed by this target. - Add 'destroy' commands to nf_tables. They are identical to the existing 'delete' commands, but do not return an error if the referenced object (set, chain, rule...) did not exist. Driver API: - Improve cpumask_local_spread() locality to help NICs set the right IRQ affinity on AMD platforms. - Separate C22 and C45 MDIO bus transactions more clearly. - Introduce new DCB table to control DSCP rewrite on egress. - Support configuration of Physical Layer Collision Avoidance (PLCA) Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of shared medium Ethernet. - Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing preemption of low priority frames by high priority frames. - Add support for controlling MACSec offload using netlink SET. - Rework devlink instance refcounts to allow registration and de-registration under the instance lock. Split the code into multiple files, drop some of the unnecessarily granular locks and factor out common parts of netlink operation handling. - Add TX frame aggregation parameters (for USB drivers). - Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning messages with notifications for debug. - Allow offloading of UDP NEW connections via act_ct. - Add support for per action HW stats in TC. - Support hardware miss to TC action (continue processing in SW from a specific point in the action chain). - Warn if old Wireless Extension user space interface is used with modern cfg80211/mac80211 drivers. Do not support Wireless Extensions for Wi-Fi 7 devices at all. Everyone should switch to using nl80211 interface instead. - Improve the CAN bit timing configuration. Use extack to return error messages directly to user space, update the SJW handling, including the definition of a new default value that will benefit CAN-FD controllers, by increasing their oscillator tolerance. New hardware / drivers: - Ethernet: - nVidia BlueField-3 support (control traffic driver) - Ethernet support for imx93 SoCs - Motorcomm yt8531 gigabit Ethernet PHY - onsemi NCN26000 10BASE-T1S PHY (with support for PLCA) - Microchip LAN8841 PHY (incl. cable diagnostics and PTP) - Amlogic gxl MDIO mux - WiFi: - RealTek RTL8188EU (rtl8xxxu) - Qualcomm Wi-Fi 7 devices (ath12k) - CAN: - Renesas R-Car V4H Drivers: - Bluetooth: - Set Per Platform Antenna Gain (PPAG) for Intel controllers. - Ethernet NICs: - Intel (1G, igc): - support TSN / Qbv / packet scheduling features of i226 model - Intel (100G, ice): - use GNSS subsystem instead of TTY - multi-buffer XDP support - extend support for GPIO pins to E823 devices - nVidia/Mellanox: - update the shared buffer configuration on PFC commands - implement PTP adjphase function for HW offset control - TC support for Geneve and GRE with VF tunnel offload - more efficient crypto key management method - multi-port eswitch support - Netronome/Corigine: - add DCB IEEE support - support IPsec offloading for NFP3800 - Freescale/NXP (enetc): - support XDP_REDIRECT for XDP non-linear buffers - improve reconfig, avoid link flap and waiting for idle - support MAC Merge layer - Other NICs: - sfc/ef100: add basic devlink support for ef100 - ionic: rx_push mode operation (writing descriptors via MMIO) - bnxt: use the auxiliary bus abstraction for RDMA - r8169: disable ASPM and reset bus in case of tx timeout - cpsw: support QSGMII mode for J721e CPSW9G - cpts: support pulse-per-second output - ngbe: add an mdio bus driver - usbnet: optimize usbnet_bh() by avoiding unnecessary queuing - r8152: handle devices with FW with NCM support - amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation - virtio-net: support multi buffer XDP - virtio/vsock: replace virtio_vsock_pkt with sk_buff - tsnep: XDP support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add support for latency TLV (in FW control messages) - Microchip (sparx5): - separate explicit and implicit traffic forwarding rules, make the implicit rules always active - add support for egress DSCP rewrite - IS0 VCAP support (Ingress Classification) - IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS etc.) - ES2 VCAP support (Egress Access Control) - support for Per-Stream Filtering and Policing (802.1Q, 8.6.5.1) - Ethernet embedded switches: - Marvell (mv88e6xxx): - add MAB (port auth) offload support - enable PTP receive for mv88e6390 - NXP (ocelot): - support MAC Merge layer - support for the the vsc7512 internal copper phys - Microchip: - lan9303: convert to PHYLINK - lan966x: support TC flower filter statistics - lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x - lan937x: support Credit Based Shaper configuration - ksz9477: support Energy Efficient Ethernet - other: - qca8k: convert to regmap read/write API, use bulk operations - rswitch: Improve TX timestamp accuracy - Intel WiFi (iwlwifi): - EHT (Wi-Fi 7) rate reporting - STEP equalizer support: transfer some STEP (connection to radio on platforms with integrated wifi) related parameters from the BIOS to the firmware. - Qualcomm 802.11ax WiFi (ath11k): - IPQ5018 support - Fine Timing Measurement (FTM) responder role support - channel 177 support - MediaTek WiFi (mt76): - per-PHY LED support - mt7996: EHT (Wi-Fi 7) support - Wireless Ethernet Dispatch (WED) reset support - switch to using page pool allocator - RealTek WiFi (rtw89): - support new version of Bluetooth co-existance - Mobile: - rmnet: support TX aggregation" * tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits) page_pool: add a comment explaining the fragment counter usage net: ethtool: fix __ethtool_dev_mm_supported() implementation ethtool: pse-pd: Fix double word in comments xsk: add linux/vmalloc.h to xsk.c sefltests: netdevsim: wait for devlink instance after netns removal selftest: fib_tests: Always cleanup before exit net/mlx5e: Align IPsec ASO result memory to be as required by hardware net/mlx5e: TC, Set CT miss to the specific ct action instance net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG net/mlx5: Refactor tc miss handling to a single function net/mlx5: Kconfig: Make tc offload depend on tc skb extension net/sched: flower: Support hardware miss to tc action net/sched: flower: Move filter handle initialization earlier net/sched: cls_api: Support hardware miss to tc action net/sched: Rename user cookie and act cookie sfc: fix builds without CONFIG_RTC_LIB sfc: clean up some inconsistent indentings net/mlx4_en: Introduce flexible array to silence overflow warning net: lan966x: Fix possible deadlock inside PTP net/ulp: Remove redundant ->clone() test in inet_clone_ulp(). ... --- drivers/media/usb/gspca/mars.c | 427 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 427 insertions(+) create mode 100644 drivers/media/usb/gspca/mars.c (limited to 'drivers/media/usb/gspca/mars.c') diff --git a/drivers/media/usb/gspca/mars.c b/drivers/media/usb/gspca/mars.c new file mode 100644 index 000000000..eb9342ee3 --- /dev/null +++ b/drivers/media/usb/gspca/mars.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Mars-Semi MR97311A library + * Copyright (C) 2005 + * + * V4L2 by Jean-Francois Moine + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#define MODULE_NAME "mars" + +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver"); +MODULE_LICENSE("GPL"); + +#define QUALITY 50 + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *sharpness; + struct v4l2_ctrl *gamma; + struct { /* illuminator control cluster */ + struct v4l2_ctrl *illum_top; + struct v4l2_ctrl *illum_bottom; + }; + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +/* V4L2 controls supported by the driver */ +static void setbrightness(struct gspca_dev *gspca_dev, s32 val); +static void setcolors(struct gspca_dev *gspca_dev, s32 val); +static void setgamma(struct gspca_dev *gspca_dev, s32 val); +static void setsharpness(struct gspca_dev *gspca_dev, s32 val); + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +static const __u8 mi_data[0x20] = { +/* 01 02 03 04 05 06 07 08 */ + 0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00, +/* 09 0a 0b 0c 0d 0e 0f 10 */ + 0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, +/* 11 12 13 14 15 16 17 18 */ + 0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02, +/* 19 1a 1b 1c 1d 1e 1f 20 */ + 0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00 +}; + +/* write bytes from gspca_dev->usb_buf */ +static void reg_w(struct gspca_dev *gspca_dev, + int len) +{ + int alen, ret; + + if (gspca_dev->usb_err < 0) + return; + + ret = usb_bulk_msg(gspca_dev->dev, + usb_sndbulkpipe(gspca_dev->dev, 4), + gspca_dev->usb_buf, + len, + &alen, + 500); /* timeout in milliseconds */ + if (ret < 0) { + pr_err("reg write [%02x] error %d\n", + gspca_dev->usb_buf[0], ret); + gspca_dev->usb_err = ret; + } +} + +static void mi_w(struct gspca_dev *gspca_dev, + u8 addr, + u8 value) +{ + gspca_dev->usb_buf[0] = 0x1f; + gspca_dev->usb_buf[1] = 0; /* control byte */ + gspca_dev->usb_buf[2] = addr; + gspca_dev->usb_buf[3] = value; + + reg_w(gspca_dev, 4); +} + +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) +{ + gspca_dev->usb_buf[0] = 0x61; + gspca_dev->usb_buf[1] = val; + reg_w(gspca_dev, 2); +} + +static void setcolors(struct gspca_dev *gspca_dev, s32 val) +{ + gspca_dev->usb_buf[0] = 0x5f; + gspca_dev->usb_buf[1] = val << 3; + gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04; + reg_w(gspca_dev, 3); +} + +static void setgamma(struct gspca_dev *gspca_dev, s32 val) +{ + gspca_dev->usb_buf[0] = 0x06; + gspca_dev->usb_buf[1] = val * 0x40; + reg_w(gspca_dev, 2); +} + +static void setsharpness(struct gspca_dev *gspca_dev, s32 val) +{ + gspca_dev->usb_buf[0] = 0x67; + gspca_dev->usb_buf[1] = val * 4 + 3; + reg_w(gspca_dev, 2); +} + +static void setilluminators(struct gspca_dev *gspca_dev, bool top, bool bottom) +{ + /* both are off if not streaming */ + gspca_dev->usb_buf[0] = 0x22; + if (top) + gspca_dev->usb_buf[1] = 0x76; + else if (bottom) + gspca_dev->usb_buf[1] = 0x7a; + else + gspca_dev->usb_buf[1] = 0x7e; + reg_w(gspca_dev, 2); +} + +static int mars_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (ctrl->id == V4L2_CID_ILLUMINATORS_1) { + /* only one can be on at a time */ + if (ctrl->is_new && ctrl->val) + sd->illum_bottom->val = 0; + if (sd->illum_bottom->is_new && sd->illum_bottom->val) + sd->illum_top->val = 0; + } + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAMMA: + setgamma(gspca_dev, ctrl->val); + break; + case V4L2_CID_ILLUMINATORS_1: + setilluminators(gspca_dev, sd->illum_top->val, + sd->illum_bottom->val); + break; + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev, ctrl->val); + break; + default: + return -EINVAL; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops mars_ctrl_ops = { + .s_ctrl = mars_s_ctrl, +}; + +/* this function is called at probe time */ +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 6); + sd->brightness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 30, 1, 15); + sd->saturation = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 200); + sd->gamma = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_GAMMA, 0, 3, 1, 1); + sd->sharpness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 2, 1, 1); + sd->illum_top = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0); + sd->illum_top->flags |= V4L2_CTRL_FLAG_UPDATE; + sd->illum_bottom = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0); + sd->illum_bottom->flags |= V4L2_CTRL_FLAG_UPDATE; + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + v4l2_ctrl_cluster(2, &sd->illum_top); + return 0; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam; + + cam = &gspca_dev->cam; + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 *data; + int i; + + /* create the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, + 0x21); /* JPEG 422 */ + jpeg_set_qual(sd->jpeg_hdr, QUALITY); + + data = gspca_dev->usb_buf; + + data[0] = 0x01; /* address */ + data[1] = 0x01; + reg_w(gspca_dev, 2); + + /* + Initialize the MR97113 chip register + */ + data[0] = 0x00; /* address */ + data[1] = 0x0c | 0x01; /* reg 0 */ + data[2] = 0x01; /* reg 1 */ + data[3] = gspca_dev->pixfmt.width / 8; /* h_size , reg 2 */ + data[4] = gspca_dev->pixfmt.height / 8; /* v_size , reg 3 */ + data[5] = 0x30; /* reg 4, MI, PAS5101 : + * 0x30 for 24mhz , 0x28 for 12mhz */ + data[6] = 0x02; /* reg 5, H start - was 0x04 */ + data[7] = v4l2_ctrl_g_ctrl(sd->gamma) * 0x40; /* reg 0x06: gamma */ + data[8] = 0x01; /* reg 7, V start - was 0x03 */ +/* if (h_size == 320 ) */ +/* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */ +/* else */ + data[9] = 0x52; /* reg 8, 24MHz, no scale down */ +/*jfm: from win trace*/ + data[10] = 0x18; + + reg_w(gspca_dev, 11); + + data[0] = 0x23; /* address */ + data[1] = 0x09; /* reg 35, append frame header */ + + reg_w(gspca_dev, 2); + + data[0] = 0x3c; /* address */ +/* if (gspca_dev->width == 1280) */ +/* data[1] = 200; * reg 60, pc-cam frame size + * (unit: 4KB) 800KB */ +/* else */ + data[1] = 50; /* 50 reg 60, pc-cam frame size + * (unit: 4KB) 200KB */ + reg_w(gspca_dev, 2); + + /* auto dark-gain */ + data[0] = 0x5e; /* address */ + data[1] = 0; /* reg 94, Y Gain (auto) */ +/*jfm: from win trace*/ + /* reg 0x5f/0x60 (LE) = saturation */ + /* h (60): xxxx x100 + * l (5f): xxxx x000 */ + data[2] = v4l2_ctrl_g_ctrl(sd->saturation) << 3; + data[3] = ((v4l2_ctrl_g_ctrl(sd->saturation) >> 2) & 0xf8) | 0x04; + data[4] = v4l2_ctrl_g_ctrl(sd->brightness); /* reg 0x61 = brightness */ + data[5] = 0x00; + + reg_w(gspca_dev, 6); + + data[0] = 0x67; +/*jfm: from win trace*/ + data[1] = v4l2_ctrl_g_ctrl(sd->sharpness) * 4 + 3; + data[2] = 0x14; + reg_w(gspca_dev, 3); + + data[0] = 0x69; + data[1] = 0x2f; + data[2] = 0x28; + data[3] = 0x42; + reg_w(gspca_dev, 4); + + data[0] = 0x63; + data[1] = 0x07; + reg_w(gspca_dev, 2); +/*jfm: win trace - many writes here to reg 0x64*/ + + /* initialize the MI sensor */ + for (i = 0; i < sizeof mi_data; i++) + mi_w(gspca_dev, i + 1, mi_data[i]); + + data[0] = 0x00; + data[1] = 0x4d; /* ISOC transferring enable... */ + reg_w(gspca_dev, 2); + + setilluminators(gspca_dev, v4l2_ctrl_g_ctrl(sd->illum_top), + v4l2_ctrl_g_ctrl(sd->illum_bottom)); + + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (v4l2_ctrl_g_ctrl(sd->illum_top) || + v4l2_ctrl_g_ctrl(sd->illum_bottom)) { + setilluminators(gspca_dev, false, false); + msleep(20); + } + + gspca_dev->usb_buf[0] = 1; + gspca_dev->usb_buf[1] = 0; + reg_w(gspca_dev, 2); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int p; + + if (len < 6) { +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + for (p = 0; p < len - 6; p++) { + if (data[0 + p] == 0xff + && data[1 + p] == 0xff + && data[2 + p] == 0x00 + && data[3 + p] == 0xff + && data[4 + p] == 0x96) { + if (data[5 + p] == 0x64 + || data[5 + p] == 0x65 + || data[5 + p] == 0x66 + || data[5 + p] == 0x67) { + gspca_dbg(gspca_dev, D_PACK, "sof offset: %d len: %d\n", + p, len); + gspca_frame_add(gspca_dev, LAST_PACKET, + data, p); + + /* put the JPEG header */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + data += p + 16; + len -= p + 16; + break; + } + } + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .init_controls = sd_init_controls, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x093a, 0x050f)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, + .reset_resume = gspca_resume, +#endif +}; + +module_usb_driver(sd_driver); -- cgit v1.2.3