uvc_status.c 5.4 KB
Newer Older
1 2 3
/*
 *      uvc_status.c  --  USB Video Class driver - Status endpoint
 *
4 5
 *      Copyright (C) 2005-2009
 *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
6 7 8 9 10 11 12 13 14 15
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 */

#include <linux/kernel.h>
#include <linux/input.h>
16
#include <linux/slab.h>
17 18 19 20 21 22 23 24
#include <linux/usb.h>
#include <linux/usb/input.h>

#include "uvcvideo.h"

/* --------------------------------------------------------------------------
 * Input device
 */
25
#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
26 27 28 29 30 31 32 33 34
static int uvc_input_init(struct uvc_device *dev)
{
	struct input_dev *input;
	int ret;

	input = input_allocate_device();
	if (input == NULL)
		return -ENOMEM;

35 36
	usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys));
	strlcat(dev->input_phys, "/button", sizeof(dev->input_phys));
37 38

	input->name = dev->name;
39 40
	input->phys = dev->input_phys;
	usb_to_input_id(dev->udev, &input->id);
41 42
	input->dev.parent = &dev->intf->dev;

43 44
	__set_bit(EV_KEY, input->evbit);
	__set_bit(KEY_CAMERA, input->keybit);
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

	if ((ret = input_register_device(input)) < 0)
		goto error;

	dev->input = input;
	return 0;

error:
	input_free_device(input);
	return ret;
}

static void uvc_input_cleanup(struct uvc_device *dev)
{
	if (dev->input)
		input_unregister_device(dev->input);
}

63 64 65
static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
	int value)
{
66
	if (dev->input) {
67
		input_report_key(dev->input, code, value);
68 69
		input_sync(dev->input);
	}
70 71 72 73 74 75 76 77
}

#else
#define uvc_input_init(dev)
#define uvc_input_cleanup(dev)
#define uvc_input_report_key(dev, code, value)
#endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
/* --------------------------------------------------------------------------
 * Status interrupt endpoint
 */
static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len)
{
	if (len < 3) {
		uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event "
				"received.\n");
		return;
	}

	if (data[2] == 0) {
		if (len < 4)
			return;
		uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n",
			data[1], data[3] ? "pressed" : "released", len);
94
		uvc_input_report_key(dev, KEY_CAMERA, data[3]);
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
	} else {
		uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x "
			"len %d.\n", data[1], data[2], data[3], len);
	}
}

static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len)
{
	char *attrs[3] = { "value", "info", "failure" };

	if (len < 6 || data[2] != 0 || data[4] > 2) {
		uvc_trace(UVC_TRACE_STATUS, "Invalid control status event "
				"received.\n");
		return;
	}

	uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n",
		data[1], data[3], attrs[data[4]], len);
}

static void uvc_status_complete(struct urb *urb)
{
	struct uvc_device *dev = urb->context;
	int len, ret;

	switch (urb->status) {
	case 0:
		break;

	case -ENOENT:		/* usb_kill_urb() called. */
	case -ECONNRESET:	/* usb_unlink_urb() called. */
	case -ESHUTDOWN:	/* The endpoint is being disabled. */
	case -EPROTO:		/* Device is disconnected (reported by some
				 * host controller). */
		return;

	default:
		uvc_printk(KERN_WARNING, "Non-zero status (%d) in status "
			"completion handler.\n", urb->status);
		return;
	}

	len = urb->actual_length;
	if (len > 0) {
		switch (dev->status[0] & 0x0f) {
		case UVC_STATUS_TYPE_CONTROL:
			uvc_event_control(dev, dev->status, len);
			break;

		case UVC_STATUS_TYPE_STREAMING:
			uvc_event_streaming(dev, dev->status, len);
			break;

		default:
149 150
			uvc_trace(UVC_TRACE_STATUS, "Unknown status event "
				"type %u.\n", dev->status[0]);
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
			break;
		}
	}

	/* Resubmit the URB. */
	urb->interval = dev->int_ep->desc.bInterval;
	if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
		uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
			ret);
	}
}

int uvc_status_init(struct uvc_device *dev)
{
	struct usb_host_endpoint *ep = dev->int_ep;
	unsigned int pipe;
	int interval;

	if (ep == NULL)
		return 0;

	uvc_input_init(dev);

174 175 176 177
	dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL);
	if (dev->status == NULL)
		return -ENOMEM;

178
	dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
179 180
	if (dev->int_urb == NULL) {
		kfree(dev->status);
181
		return -ENOMEM;
182
	}
183 184 185 186 187 188 189 190 191 192 193 194

	pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);

	/* For high-speed interrupt endpoints, the bInterval value is used as
	 * an exponent of two. Some developers forgot about it.
	 */
	interval = ep->desc.bInterval;
	if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
	    (dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
		interval = fls(interval) - 1;

	usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
195
		dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
196 197
		dev, interval);

198
	return 0;
199 200 201 202 203 204
}

void uvc_status_cleanup(struct uvc_device *dev)
{
	usb_kill_urb(dev->int_urb);
	usb_free_urb(dev->int_urb);
205
	kfree(dev->status);
206 207 208
	uvc_input_cleanup(dev);
}

209 210 211 212 213 214 215 216 217
int uvc_status_start(struct uvc_device *dev)
{
	if (dev->int_urb == NULL)
		return 0;

	return usb_submit_urb(dev->int_urb, GFP_KERNEL);
}

void uvc_status_stop(struct uvc_device *dev)
218 219
{
	usb_kill_urb(dev->int_urb);
220 221 222 223 224 225 226
}

int uvc_status_suspend(struct uvc_device *dev)
{
	if (atomic_read(&dev->users))
		usb_kill_urb(dev->int_urb);

227 228 229 230 231
	return 0;
}

int uvc_status_resume(struct uvc_device *dev)
{
232
	if (dev->int_urb == NULL || atomic_read(&dev->users) == 0)
233 234
		return 0;

235
	return usb_submit_urb(dev->int_urb, GFP_NOIO);
236
}
237