drivers/media/usb/siano/smsusb.c

Source file repositories/reference/linux-study-clean/drivers/media/usb/siano/smsusb.c

File Facts

System
Linux kernel
Corpus path
drivers/media/usb/siano/smsusb.c
Extension
.c
Size
19809 bytes
Lines
737
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct smsusb_urb_t {
	struct list_head entry;
	struct smscore_buffer_t *cb;
	struct smsusb_device_t *dev;

	struct urb *urb;

	/* For the bottom half */
	struct work_struct wq;
};

struct smsusb_device_t {
	struct usb_device *udev;
	struct smscore_device_t *coredev;

	struct smsusb_urb_t	surbs[MAX_URBS];

	int		response_alignment;
	int		buffer_size;

	unsigned char in_ep;
	unsigned char out_ep;
	enum smsusb_state state;
};

static int smsusb_submit_urb(struct smsusb_device_t *dev,
			     struct smsusb_urb_t *surb);

/*
 * Completing URB's callback handler - bottom half (process context)
 * submits the URB prepared on smsusb_onresponse()
 */
static void do_submit_urb(struct work_struct *work)
{
	struct smsusb_urb_t *surb = container_of(work, struct smsusb_urb_t, wq);
	struct smsusb_device_t *dev = surb->dev;

	smsusb_submit_urb(dev, surb);
}

/*
 * Completing URB's callback handler - top half (interrupt context)
 * adds completing sms urb to the global surbs list and activtes the worker
 * thread the surb
 * IMPORTANT - blocking functions must not be called from here !!!

 * @param urb pointer to a completing urb object
 */
static void smsusb_onresponse(struct urb *urb)
{
	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
	struct smsusb_device_t *dev = surb->dev;

	if (urb->status == -ESHUTDOWN) {
		pr_err("error, urb status %d (-ESHUTDOWN), %d bytes\n",
			urb->status, urb->actual_length);
		return;
	}

	if ((urb->actual_length > 0) && (urb->status == 0)) {
		struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)surb->cb->p;

		smsendian_handle_message_header(phdr);
		if (urb->actual_length >= phdr->msg_length) {
			surb->cb->size = phdr->msg_length;

			if (dev->response_alignment &&
			    (phdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG)) {

				surb->cb->offset =
					dev->response_alignment +
					((phdr->msg_flags >> 8) & 3);

				/* sanity check */
				if (((int) phdr->msg_length +
				     surb->cb->offset) > urb->actual_length) {
					pr_err("invalid response msglen %d offset %d size %d\n",
						phdr->msg_length,
						surb->cb->offset,
						urb->actual_length);
					goto exit_and_resubmit;
				}

				/* move buffer pointer and
				 * copy header to its new location */
				memcpy((char *) phdr + surb->cb->offset,
				       phdr, sizeof(struct sms_msg_hdr));
			} else
				surb->cb->offset = 0;

Annotation

Implementation Notes