/* * Returns zero if the message was successfully queued, or a negative errno * otherwise. */ static int message_send(struct greybus_host_device *hd, u16 cport_id, struct gb_message *message, gfp_t gfp_mask) { struct es1_ap_dev *es1 = hd_to_es1(hd); struct usb_device *udev = es1->usb_dev; size_t buffer_size; int retval; struct urb *urb; int ep_pair; unsigned long flags; /* * The data actually transferred will include an indication * of where the data should be sent. Do one last check of * the target CPort id before filling it in. */ if (!cport_id_valid(hd, cport_id)) { pr_err("invalid destination cport 0x%02x\n", cport_id); return -EINVAL; } /* Find a free urb */ urb = next_free_urb(es1, gfp_mask); if (!urb) return -ENOMEM; spin_lock_irqsave(&es1->cport_out_urb_lock, flags); message->hcpriv = urb; spin_unlock_irqrestore(&es1->cport_out_urb_lock, flags); /* Pack the cport id into the message header */ gb_message_cport_pack(message->header, cport_id); buffer_size = sizeof(*message->header) + message->payload_size; ep_pair = cport_to_ep_pair(es1, cport_id); usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, es1->cport_out[ep_pair].endpoint), message->buffer, buffer_size, cport_out_callback, message); urb->transfer_flags |= URB_ZERO_PACKET; trace_gb_host_device_send(hd, cport_id, buffer_size); retval = usb_submit_urb(urb, gfp_mask); if (retval) { pr_err("error %d submitting URB\n", retval); spin_lock_irqsave(&es1->cport_out_urb_lock, flags); message->hcpriv = NULL; spin_unlock_irqrestore(&es1->cport_out_urb_lock, flags); free_urb(es1, urb); gb_message_cport_clear(message->header); return retval; } return 0; }
/* Extract the CPort id packed into the header, and clear it */ static u16 gb_message_cport_unpack(struct gb_operation_msg_hdr *header) { u16 cport_id = header->pad[0]; gb_message_cport_clear(header); return cport_id; }
static void cport_out_callback(struct urb *urb) { struct gb_message *message = urb->context; struct gb_host_device *hd = message->operation->connection->hd; struct es2_ap_dev *es2 = hd_to_es2(hd); int status = check_urb_status(urb); unsigned long flags; gb_message_cport_clear(message->header); spin_lock_irqsave(&es2->cport_out_urb_lock, flags); message->hcpriv = NULL; spin_unlock_irqrestore(&es2->cport_out_urb_lock, flags); /* * Tell the submitter that the message send (attempt) is * complete, and report the status. */ greybus_message_sent(hd, message, status); free_urb(es2, urb); }