// SPDX-License-Identifier: GPL-2.0-or-later /* * gspca ViCam subdriver * * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> * * Based on the usbvideo vicam driver, which is: * * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), * Chris Cheney (chris.cheney@gmail.com), * Pavel Machek (pavel@ucw.cz), * John Tyner (jtyner@cs.ucr.edu), * Monroe Williams (monroe@pobox.com)
*/
/* * This function is called as a workqueue function and runs whenever the camera * is streaming data. Because it is a workqueue function it is allowed to sleep * so we can use synchronous USB calls. To avoid possible collisions with other * threads attempting to use gspca_dev->usb_buf we take the usb_lock when * performing USB operations using it. In practice we don't really need this * as the cameras controls are only written from the workqueue.
*/ staticvoid vicam_dostream(struct work_struct *work)
{ struct sd *sd = container_of(work, struct sd, work_struct); struct gspca_dev *gspca_dev = &sd->gspca_dev; int ret, frame_sz;
u8 *buffer;
frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage +
HEADER_SIZE;
buffer = kmalloc(frame_sz, GFP_KERNEL); if (!buffer) {
pr_err("Couldn't allocate USB buffer\n"); gotoexit;
}
while (gspca_dev->present && gspca_dev->streaming) { #ifdef CONFIG_PM if (gspca_dev->frozen) break; #endif
ret = vicam_read_frame(gspca_dev, buffer, frame_sz); if (ret < 0) break;
/* Note the frame header contents seem to be completely constant, they do not change with either image, or settings. So we simply discard it. The frames have a very similar 64 byte footer, which we don't even
bother reading from the cam */
gspca_frame_add(gspca_dev, FIRST_PACKET,
buffer + HEADER_SIZE,
frame_sz - HEADER_SIZE);
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
} exit:
kfree(buffer);
}
/* This function is called at probe time just before sd_init */ staticint sd_config(struct gspca_dev *gspca_dev, conststruct usb_device_id *id)
{ struct cam *cam = &gspca_dev->cam; struct sd *sd = (struct sd *)gspca_dev;
/* We don't use the buffer gspca allocates so make it small. */
cam->bulk = 1;
cam->bulk_size = 64;
cam->cam_mode = vicam_mode;
cam->nmodes = ARRAY_SIZE(vicam_mode);
INIT_WORK(&sd->work_struct, vicam_dostream);
return 0;
}
/* this function is called at probe and resume time */ staticint sd_init(struct gspca_dev *gspca_dev)
{ int ret; conststruct ihex_binrec *rec; conststruct firmware *fw;
u8 *firmware_buf; int len;
ret = request_ihex_firmware(&fw, VICAM_FIRMWARE,
&gspca_dev->dev->dev); if (ret) {
pr_err("Failed to load \"vicam/firmware.fw\": %d\n", ret); return ret;
}
firmware_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!firmware_buf) {
ret = -ENOMEM; gotoexit;
} for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {
len = be16_to_cpu(rec->len); if (len > PAGE_SIZE) {
ret = -EINVAL; break;
}
memcpy(firmware_buf, rec->data, len);
ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf,
len); if (ret < 0) break;
}
/* Set up for getting frames. */ staticint sd_start(struct gspca_dev *gspca_dev)
{ struct sd *sd = (struct sd *)gspca_dev; int ret;
ret = vicam_set_camera_power(gspca_dev, 1); if (ret < 0) return ret;
schedule_work(&sd->work_struct);
return 0;
}
/* called on streamoff with alt==0 and on disconnect */ /* the usb_lock is held at entry - restore on exit */ staticvoid sd_stop0(struct gspca_dev *gspca_dev)
{ struct sd *dev = (struct sd *)gspca_dev;
/* wait for the work queue to terminate */
mutex_unlock(&gspca_dev->usb_lock); /* This waits for vicam_dostream to finish */
flush_work(&dev->work_struct);
mutex_lock(&gspca_dev->usb_lock);
if (gspca_dev->present)
vicam_set_camera_power(gspca_dev, 0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.