int htp_hdrs_completecb(llhttp_t *htp) {
  int rv;
  auto upstream = static_cast<HttpsUpstream *>(htp->data);
  if (LOG_ENABLED(INFO)) {
    ULOG(INFO, upstream) << "HTTP request headers completed";
  }

  auto handler = upstream->get_client_handler();

  auto downstream = upstream->get_downstream();
  auto &req = downstream->request();

  auto lgconf = log_config();
  lgconf->update_tstamp(std::chrono::system_clock::now());
  req.tstamp = lgconf->tstamp;

  req.http_major = htp->http_major;
  req.http_minor = htp->http_minor;

  req.connection_close = !llhttp_should_keep_alive(htp);

  handler->stop_read_timer();

  auto method = req.method;

  if (LOG_ENABLED(INFO)) {
    std::stringstream ss;
    ss << http2::to_method_string(method) << " "
       << (method == HTTP_CONNECT ? req.authority : req.path) << " "
       << "HTTP/" << req.http_major << "." << req.http_minor << "\n";

    for (const auto &kv : req.fs.headers()) {
      if (kv.name == "authorization") {
        ss << TTY_HTTP_HD << kv.name << TTY_RST << ": <redacted>\n";
        continue;
      }
      ss << TTY_HTTP_HD << kv.name << TTY_RST << ": " << kv.value << "\n";
    }

    ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
  }

  // set content-length if method is not CONNECT, and no
  // transfer-encoding is given.  If transfer-encoding is given, leave
  // req.fs.content_length to -1.
  if (method != HTTP_CONNECT && !req.fs.header(http2::HD_TRANSFER_ENCODING)) {
    // llhttp sets 0 to htp->content_length if there is no
    // content-length header field.  If we don't have both
    // transfer-encoding and content-length header field, we assume
    // that there is no request body.
    req.fs.content_length = htp->content_length;
  }

  auto host = req.fs.header(http2::HD_HOST);

  if (req.http_major > 1 || req.http_minor > 1) {
    req.http_major = 1;
    req.http_minor = 1;
    return -1;
  }

  if (req.http_major == 1 && req.http_minor == 1 && !host) {
    return -1;
  }

  if (host) {
    const auto &value = host->value;
    // Not allow at least '"' or '\' in host.  They are illegal in
    // authority component, also they cause headaches when we put them
    // in quoted-string.
    if (std::find_if(std::begin(value), std::end(value), [](char c) {
          return c == '"' || c == '\\';
        }) != std::end(value)) {
      return -1;
    }
  }

  downstream->inspect_http1_request();

  auto faddr = handler->get_upstream_addr();
  auto &balloc = downstream->get_block_allocator();
  auto config = get_config();

  if (method != HTTP_CONNECT) {
    http_parser_url u{};
    rv = http_parser_parse_url(req.path.c_str(), req.path.size(), 0, &u);
    if (rv != 0) {
      // Expect to respond with 400 bad request
      return -1;
    }
    // checking UF_HOST could be redundant, but just in case ...
    if (!(u.field_set & (1 << UF_SCHEMA)) || !(u.field_set & (1 << UF_HOST))) {
      req.no_authority = true;

      if (method == HTTP_OPTIONS && req.path == StringRef::from_lit("*")) {
        req.path = StringRef{};
      } else {
        req.path = http2::rewrite_clean_path(balloc, req.path);
      }

      if (host) {
        req.authority = host->value;
      }

      if (handler->get_ssl()) {
        req.scheme = StringRef::from_lit("https");
      } else {
        req.scheme = StringRef::from_lit("http");
      }
    } else {
      rewrite_request_host_path_from_uri(balloc, req, req.path, u);
    }
  }

  downstream->set_request_state(DownstreamState::HEADER_COMPLETE);

#ifdef HAVE_MRUBY
  auto worker = handler->get_worker();
  auto mruby_ctx = worker->get_mruby_context();

  auto &resp = downstream->response();

  if (mruby_ctx->run_on_request_proc(downstream) != 0) {
    resp.http_status = 500;
    return -1;
  }
#endif // HAVE_MRUBY

  // mruby hook may change method value

  if (req.no_authority && config->http2_proxy &&
      faddr->alt_mode == UpstreamAltMode::NONE) {
    // Request URI should be absolute-form for client proxy mode
    return -1;
  }

  if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
    return 0;
  }

  DownstreamConnection *dconn_ptr;

  for (;;) {
    auto dconn = handler->get_downstream_connection(rv, downstream);

    if (!dconn) {
      if (rv == SHRPX_ERR_TLS_REQUIRED) {
        upstream->redirect_to_https(downstream);
      }
      downstream->set_request_state(DownstreamState::CONNECT_FAIL);
      return -1;
    }

#ifdef HAVE_MRUBY
    dconn_ptr = dconn.get();
#endif // HAVE_MRUBY
    if (downstream->attach_downstream_connection(std::move(dconn)) == 0) {
      break;
    }
  }

#ifdef HAVE_MRUBY
  const auto &group = dconn_ptr->get_downstream_addr_group();
  if (group) {
    const auto &dmruby_ctx = group->mruby_ctx;

    if (dmruby_ctx->run_on_request_proc(downstream) != 0) {
      resp.http_status = 500;
      return -1;
    }

    if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
      return 0;
    }
  }
#endif // HAVE_MRUBY

  rv = downstream->push_request_headers();

  if (rv != 0) {
    return -1;
  }

  if (faddr->alt_mode != UpstreamAltMode::NONE) {
    // Normally, we forward expect: 100-continue to backend server,
    // and let them decide whether responds with 100 Continue or not.
    // For alternative mode, we have no backend, so just send 100
    // Continue here to make the client happy.
    if (downstream->get_expect_100_continue()) {
      auto output = downstream->get_response_buf();
      constexpr auto res = StringRef::from_lit("HTTP/1.1 100 Continue\r\n\r\n");
      output->append(res);
      handler->signal_write();
    }
  }

  return 0;
}


int32_t Downstream::get_assoc_stream_id() const { return assoc_stream_id_; }


int Downstream::resume_read(IOCtrlReason reason, size_t consumed) {
  if (dconn_) {
    return dconn_->resume_read(reason, consumed);
  }

  return 0;
}


int HttpDownstreamConnection::write_tls() {
  conn_.last_read = ev_now(conn_.loop);

  ERR_clear_error();

  auto upstream = downstream_->get_upstream();
  auto input = downstream_->get_request_buf();

  struct iovec iov;

  while (input->rleft() > 0) {
    auto iovcnt = input->riovec(&iov, 1);
    if (iovcnt != 1) {
      assert(0);
      return -1;
    }
    auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len);

    if (nwrite == 0) {
      return 0;
    }

    if (nwrite < 0) {
      if (!first_write_done_) {
        return nwrite;
      }
      // We may have pending data in receive buffer which may contain
      // part of response body.  So keep reading.  Invoke read event
      // to get read(2) error just in case.
      ev_feed_event(conn_.loop, &conn_.rev, EV_READ);
      on_write_ = &HttpDownstreamConnection::noop;
      reusable_ = false;
      break;
    }

    input->drain(nwrite);
  }

  conn_.wlimit.stopw();
  ev_timer_stop(conn_.loop, &conn_.wt);

  if (input->rleft() == 0) {
    auto &req = downstream_->request();

    upstream->resume_read(SHRPX_NO_BUFFER, downstream_,
                          req.unconsumed_body_length);
  }

  return 0;
}


DefaultMemchunks *Downstream::get_blocked_request_buf() {
  return &blocked_request_buf_;
}


DefaultMemchunks *Downstream::get_request_buf() { return &request_buf_; }


vhost_user_set_vring_num(struct virtio_net **pdev,
			struct VhostUserMsg *msg,
			int main_fd __rte_unused)
{
	struct virtio_net *dev = *pdev;
	struct vhost_virtqueue *vq = dev->virtqueue[msg->payload.state.index];

	if (validate_msg_fds(msg, 0) != 0)
		return RTE_VHOST_MSG_RESULT_ERR;

	vq->size = msg->payload.state.num;

	/* VIRTIO 1.0, 2.4 Virtqueues says:
	 *
	 *   Queue Size value is always a power of 2. The maximum Queue Size
	 *   value is 32768.
	 *
	 * VIRTIO 1.1 2.7 Virtqueues says:
	 *
	 *   Packed virtqueues support up to 2^15 entries each.
	 */
	if (!vq_is_packed(dev)) {
		if (vq->size & (vq->size - 1)) {
			RTE_LOG(ERR, VHOST_CONFIG,
				"invalid virtqueue size %u\n", vq->size);
			return RTE_VHOST_MSG_RESULT_ERR;
		}
	}

	if (vq->size > 32768) {
		RTE_LOG(ERR, VHOST_CONFIG,
			"invalid virtqueue size %u\n", vq->size);
		return RTE_VHOST_MSG_RESULT_ERR;
	}

	if (dev->dequeue_zero_copy) {
		vq->nr_zmbuf = 0;
		vq->last_zmbuf_idx = 0;
		vq->zmbuf_size = vq->size;
		if (vq->zmbufs)
			rte_free(vq->zmbufs);
		vq->zmbufs = rte_zmalloc(NULL, vq->zmbuf_size *
					 sizeof(struct zcopy_mbuf), 0);
		if (vq->zmbufs == NULL) {
			RTE_LOG(WARNING, VHOST_CONFIG,
				"failed to allocate mem for zero copy; "
				"zero copy is force disabled\n");
			dev->dequeue_zero_copy = 0;
		}
		TAILQ_INIT(&vq->zmbuf_list);
	}

	if (vq_is_packed(dev)) {
		if (vq->shadow_used_packed)
			rte_free(vq->shadow_used_packed);
		vq->shadow_used_packed = rte_malloc(NULL,
				vq->size *
				sizeof(struct vring_used_elem_packed),
				RTE_CACHE_LINE_SIZE);
		if (!vq->shadow_used_packed) {
			RTE_LOG(ERR, VHOST_CONFIG,
					"failed to allocate memory for shadow used ring.\n");
			return RTE_VHOST_MSG_RESULT_ERR;
		}

	} else {
		if (vq->shadow_used_split)
			rte_free(vq->shadow_used_split);
		vq->shadow_used_split = rte_malloc(NULL,
				vq->size * sizeof(struct vring_used_elem),
				RTE_CACHE_LINE_SIZE);
		if (!vq->shadow_used_split) {
			RTE_LOG(ERR, VHOST_CONFIG,
					"failed to allocate memory for shadow used ring.\n");
			return RTE_VHOST_MSG_RESULT_ERR;
		}
	}

	if (vq->batch_copy_elems)
		rte_free(vq->batch_copy_elems);
	vq->batch_copy_elems = rte_malloc(NULL,
				vq->size * sizeof(struct batch_copy_elem),
				RTE_CACHE_LINE_SIZE);
	if (!vq->batch_copy_elems) {
		RTE_LOG(ERR, VHOST_CONFIG,
			"failed to allocate memory for batching copy.\n");
		return RTE_VHOST_MSG_RESULT_ERR;
	}

	return RTE_VHOST_MSG_RESULT_OK;
}


static int vhost_user_set_vring_err(struct virtio_net **pdev __rte_unused,
			struct VhostUserMsg *msg,
			int main_fd __rte_unused)
{
	if (validate_msg_fds(msg, 1) != 0)
		return RTE_VHOST_MSG_RESULT_ERR;

	if (!(msg->payload.u64 & VHOST_USER_VRING_NOFD_MASK))
		close(msg->fds[0]);
	RTE_LOG(INFO, VHOST_CONFIG, "not implemented\n");

	return RTE_VHOST_MSG_RESULT_OK;
}


ippGetVersion(ipp_t *ipp,		/* I - IPP message */
              int   *minor)		/* O - Minor version number or @code NULL@ for don't care */
{
 /*
  * Range check input...
  */

  if (!ipp)
  {
    if (minor)
      *minor = 0;

    return (0);
  }

 /*
  * Return the value...
  */

  if (minor)
    *minor = ipp->request.any.version[1];

  return (ipp->request.any.version[0]);
}


_cupsBufferGet(size_t size)		/* I - Size required */
{
  _cups_buffer_t	*buffer;	/* Current buffer */
  _cups_globals_t	*cg = _cupsGlobals();
					/* Global data */

  for (buffer = cg->cups_buffers; buffer; buffer = buffer->next)
    if (!buffer->used && buffer->size >= size)
      break;

  if (!buffer)
  {
    if ((buffer = malloc(sizeof(_cups_buffer_t) + size - 1)) == NULL)
      return (NULL);

    buffer->next     = cg->cups_buffers;
    buffer->size     = size;
    cg->cups_buffers = buffer;
  }

  buffer->used = 1;

  return (buffer->d);
}


httpConnect(const char *host,		/* I - Host to connect to */
            int        port)		/* I - Port number */
{
  return (httpConnect2(host, port, NULL, AF_UNSPEC,
                       HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL));
}


snmp_set_error(cups_snmp_t *packet,	/* I - Packet */
               const char *message)	/* I - Error message */
{
  _cups_globals_t *cg = _cupsGlobals();	/* Global data */

  if (!cg->lang_default)
    cg->lang_default = cupsLangDefault();

  packet->error = _cupsLangString(cg->lang_default, message);
}


httpGetLength(http_t *http)		/* I - HTTP connection */
{
 /*
  * Get the read content length and return the 32-bit value.
  */

  if (http)
  {
    httpGetLength2(http);

    return (http->_data_remaining);
  }
  else
    return (-1);
}


_cupsSNMPOIDToString(const int *src,	/* I - OID */
                     char      *dst,	/* I - String buffer */
                     size_t    dstsize)	/* I - Size of string buffer */
{
  char	*dstptr,			/* Pointer into string buffer */
	*dstend;			/* End of string buffer */

  DEBUG_printf(("4_cupsSNMPOIDToString(src=%p, dst=%p, dstsize=" CUPS_LLFMT ")",
                src, dst, CUPS_LLCAST dstsize));

 /*
  * Range check input...
  */

  if (!src || !dst || dstsize < 4)
    return (NULL);

 /*
  * Loop through the OID array and build a string...
  */

  for (dstptr = dst, dstend = dstptr + dstsize - 1;
       *src >= 0 && dstptr < dstend;
       src ++, dstptr += strlen(dstptr))
    snprintf(dstptr, (size_t)(dstend - dstptr + 1), ".%d", *src);

  if (*src >= 0)
    return (NULL);
  else
    return (dst);
}


httpFreeCredentials(
    cups_array_t *credentials)		/* I - Array of credentials */
{
  http_credential_t	*credential;	/* Credential */

  for (credential = (http_credential_t *)cupsArrayFirst(credentials);
       credential;
       credential = (http_credential_t *)cupsArrayNext(credentials))
  {
    cupsArrayRemove(credentials, credential);
    free((void *)credential->data);
    free(credential);
  }

  cupsArrayDelete(credentials);
}


httpReconnect(http_t *http)		/* I - HTTP connection */
{
  DEBUG_printf(("httpReconnect(http=%p)", (void *)http));

  return (httpReconnect2(http, 30000, NULL));
}


ippTimeToDate(time_t t)			/* I - Time in seconds */
{
  struct tm	*unixdate;		/* UNIX unixdate/time info */
  ipp_uchar_t	*date = _cupsGlobals()->ipp_date;
					/* RFC-2579 date/time data */

 /*
  * RFC-2579 date/time format is:
  *
  *    Byte(s)  Description
  *    -------  -----------
  *    0-1      Year (0 to 65535)
  *    2        Month (1 to 12)
  *    3        Day (1 to 31)
  *    4        Hours (0 to 23)
  *    5        Minutes (0 to 59)
  *    6        Seconds (0 to 60, 60 = "leap second")
  *    7        Deciseconds (0 to 9)
  *    8        +/- UTC
  *    9        UTC hours (0 to 11)
  *    10       UTC minutes (0 to 59)
  */

  unixdate = gmtime(&t);
  unixdate->tm_year += 1900;

  date[0]  = (ipp_uchar_t)(unixdate->tm_year >> 8);
  date[1]  = (ipp_uchar_t)(unixdate->tm_year);
  date[2]  = (ipp_uchar_t)(unixdate->tm_mon + 1);
  date[3]  = (ipp_uchar_t)unixdate->tm_mday;
  date[4]  = (ipp_uchar_t)unixdate->tm_hour;
  date[5]  = (ipp_uchar_t)unixdate->tm_min;
  date[6]  = (ipp_uchar_t)unixdate->tm_sec;
  date[7]  = 0;
  date[8]  = '+';
  date[9]  = 0;
  date[10] = 0;

  return (date);
}


httpWait(http_t *http,			/* I - HTTP connection */
         int    msec)			/* I - Milliseconds to wait */
{
 /*
  * First see if there is data in the buffer...
  */

  DEBUG_printf(("2httpWait(http=%p, msec=%d)", (void *)http, msec));

  if (http == NULL)
    return (0);

  if (http->used)
  {
    DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
    return (1);
  }

#ifdef HAVE_LIBZ
  if (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in > 0)
  {
    DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
    return (1);
  }
#endif /* HAVE_LIBZ */

 /*
  * Flush pending data, if any...
  */

  if (http->wused)
  {
    DEBUG_puts("3httpWait: Flushing write buffer.");

    if (httpFlushWrite(http) < 0)
      return (0);
  }

 /*
  * If not, check the SSL/TLS buffers and do a select() on the connection...
  */

  return (_httpWait(http, msec, 1));
}


ippGetCollection(
    ipp_attribute_t *attr,		/* I - IPP attribute */
    int             element)		/* I - Value number (0-based) */
{
 /*
  * Range check input...
  */

  if (!attr || attr->value_tag != IPP_TAG_BEGIN_COLLECTION ||
      element < 0 || element >= attr->num_values)
    return (NULL);

 /*
  * Return the value...
  */

  return (attr->values[element].collection);
}


_cupsSNMPCopyOID(int       *dst,	/* I - Destination OID */
                 const int *src,	/* I - Source OID */
		 int       dstsize)	/* I - Number of integers in dst */
{
  int	i;				/* Looping var */

  DEBUG_printf(("4_cupsSNMPCopyOID(dst=%p, src=%p, dstsize=%d)", dst, src,
                dstsize));

  for (i = 0, dstsize --; src[i] >= 0 && i < dstsize; i ++)
    dst[i] = src[i];

  dst[i] = -1;

  return (dst);
}


ipp_lang_code(const char *locale,	/* I - Locale string */
              char       *buffer,	/* I - String buffer */
              size_t     bufsize)	/* I - Size of string buffer */
{
 /*
  * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
  */

  if (!_cups_strcasecmp(locale, "c"))
  {
    strlcpy(buffer, "en", bufsize);
    return (buffer);
  }
  else
    return (ipp_get_code(locale, buffer, bufsize));
}


ippWriteFile(int   fd,			/* I - HTTP data */
             ipp_t *ipp)		/* I - IPP data */
{
  DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, (void *)ipp));

  ipp->state = IPP_STATE_IDLE;

  return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
}


ipp_read_http(http_t      *http,	/* I - Client connection */
              ipp_uchar_t *buffer,	/* O - Buffer for data */
	      size_t      length)	/* I - Total length */
{
  ssize_t	tbytes,			/* Total bytes read */
		bytes;			/* Bytes read this pass */

  DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)", (void *)http, (void *)buffer, (int)length));

 /*
  * Loop until all bytes are read...
  */

  for (tbytes = 0, bytes = 0;
       tbytes < (int)length;
       tbytes += bytes, buffer += bytes)
  {
    DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state));

    if (http->state == HTTP_STATE_WAITING)
      break;

    if (http->used == 0 && !http->blocking)
    {
     /*
      * Wait up to 10 seconds for more data on non-blocking sockets...
      */

      if (!httpWait(http, 10000))
      {
       /*
	* Signal no data...
	*/

	bytes = -1;
	break;
      }
    }
    else if (http->used == 0 && http->timeout_value > 0)
    {
     /*
      * Wait up to timeout seconds for more data on blocking sockets...
      */

      if (!httpWait(http, (int)(1000 * http->timeout_value)))
      {
       /*
	* Signal no data...
	*/

	bytes = -1;
	break;
      }
    }

    if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0)
    {
#ifdef _WIN32
      break;
#else
      if (errno != EAGAIN && errno != EINTR)
	break;

      bytes = 0;
#endif /* _WIN32 */
    }
    else if (bytes == 0)
      break;
  }

 /*
  * Return the number of bytes read...
  */

  if (tbytes == 0 && bytes < 0)
    tbytes = -1;

  DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes));

  return (tbytes);
}


ippGetRange(ipp_attribute_t *attr,	/* I - IPP attribute */
	    int             element,	/* I - Value number (0-based) */
	    int             *uppervalue)/* O - Upper value of range */
{
 /*
  * Range check input...
  */

  if (!attr || attr->value_tag != IPP_TAG_RANGE ||
      element < 0 || element >= attr->num_values)
  {
    if (uppervalue)
      *uppervalue = 0;

    return (0);
  }

 /*
  * Return the values...
  */

  if (uppervalue)
    *uppervalue = attr->values[element].range.upper;

  return (attr->values[element].range.lower);
}


_cupsSNMPDefaultCommunity(void)
{
  cups_file_t	*fp;			/* snmp.conf file */
  char		line[1024],		/* Line from file */
		*value;			/* Value from file */
  int		linenum;		/* Line number in file */
  _cups_globals_t *cg = _cupsGlobals();	/* Global data */

  DEBUG_puts("4_cupsSNMPDefaultCommunity()");

  if (!cg->snmp_community[0])
  {
    strlcpy(cg->snmp_community, "public", sizeof(cg->snmp_community));

    snprintf(line, sizeof(line), "%s/snmp.conf", cg->cups_serverroot);
    if ((fp = cupsFileOpen(line, "r")) != NULL)
    {
      linenum = 0;
      while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
	if (!_cups_strcasecmp(line, "Community") && value)
	{
	  strlcpy(cg->snmp_community, value, sizeof(cg->snmp_community));
	  break;
	}

      cupsFileClose(fp);
    }
  }

  DEBUG_printf(("5_cupsSNMPDefaultCommunity: Returning \"%s\"",
                cg->snmp_community));

  return (cg->snmp_community);
}


httpHead(http_t     *http,		/* I - HTTP connection */
         const char *uri)		/* I - URI for head */
{
  DEBUG_printf(("httpHead(http=%p, uri=\"%s\")", (void *)http, uri));
  return (http_send(http, HTTP_STATE_HEAD, uri));
}


httpGetSubField(http_t       *http,	/* I - HTTP connection */
                http_field_t field,	/* I - Field index */
                const char   *name,	/* I - Name of sub-field */
		char         *value)	/* O - Value string */
{
  return (httpGetSubField2(http, field, name, value, HTTP_MAX_VALUE));
}


httpSetExpect(http_t        *http,	/* I - HTTP connection */
              http_status_t expect)	/* I - HTTP status to expect
              				       (@code HTTP_STATUS_CONTINUE@) */
{
  DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", (void *)http, expect));

  if (http)
    http->expect = expect;
}


httpSetField(http_t       *http,	/* I - HTTP connection */
             http_field_t field,	/* I - Field index */
	     const char   *value)	/* I - Value */
{
  DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));

  if (http == NULL ||
      field < HTTP_FIELD_ACCEPT_LANGUAGE ||
      field >= HTTP_FIELD_MAX ||
      value == NULL)
    return;

  http_add_field(http, field, value, 0);
}


ipp_set_value(ipp_t           *ipp,	/* IO - IPP message */
              ipp_attribute_t **attr,	/* IO - IPP attribute */
              int             element)	/* I  - Value number (0-based) */
{
  ipp_attribute_t	*temp,		/* New attribute pointer */
			*current,	/* Current attribute in list */
			*prev;		/* Previous attribute in list */
  int			alloc_values;	/* Allocated values */

 /*
  * If we are setting an existing value element, return it...
  */

  temp = *attr;

  if (temp->num_values <= 1)
    alloc_values = 1;
  else
    alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) &
                   ~(IPP_MAX_VALUES - 1);

  if (element < alloc_values)
  {
    if (element >= temp->num_values)
      temp->num_values = element + 1;

    return (temp->values + element);
  }

 /*
  * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
  * values when num_values > 1.
  */

  if (alloc_values < IPP_MAX_VALUES)
    alloc_values = IPP_MAX_VALUES;
  else
    alloc_values += IPP_MAX_VALUES;

  DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
                alloc_values));

 /*
  * Reallocate memory...
  */

  if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL)
  {
    _cupsSetHTTPError(HTTP_STATUS_ERROR);
    DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
    return (NULL);
  }

 /*
  * Zero the new memory...
  */

  memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t));

  if (temp != *attr)
  {
   /*
    * Reset pointers in the list...
    */

    DEBUG_printf(("4debug_free: %p %s", (void *)*attr, temp->name));
    DEBUG_printf(("4debug_alloc: %p %s %s%s (%d)", (void *)temp, temp->name, temp->num_values > 1 ? "1setOf " : "", ippTagString(temp->value_tag), temp->num_values));

    if (ipp->current == *attr && ipp->prev)
    {
     /*
      * Use current "previous" pointer...
      */

      prev = ipp->prev;
    }
    else
    {
     /*
      * Find this attribute in the linked list...
      */

      for (prev = NULL, current = ipp->attrs;
	   current && current != *attr;
	   prev = current, current = current->next);

      if (!current)
      {
       /*
	* This is a serious error!
	*/

	*attr = temp;
	_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
	              _("IPP attribute is not a member of the message."), 1);
	DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
	return (NULL);
      }
    }

    if (prev)
      prev->next = temp;
    else
      ipp->attrs = temp;

    ipp->current = temp;
    ipp->prev    = prev;

    if (ipp->last == *attr)
      ipp->last = temp;

    *attr = temp;
  }

 /*
  * Return the value element...
  */

  if (element >= temp->num_values)
    temp->num_values = element + 1;

  return (temp->values + element);
}


http_content_coding_finish(
    http_t *http)			/* I - HTTP connection */
{
  int		zerr;			/* Compression status */
  Byte		dummy[1];		/* Dummy read buffer */
  size_t	bytes;			/* Number of bytes to write */

  DEBUG_printf(("http_content_coding_finish(http=%p)", (void *)http));
  DEBUG_printf(("1http_content_coding_finishing: http->coding=%d", http->coding));

  switch (http->coding)
  {
    case _HTTP_CODING_DEFLATE :
    case _HTTP_CODING_GZIP :
        ((z_stream *)http->stream)->next_in  = dummy;
        ((z_stream *)http->stream)->avail_in = 0;

        do
        {
          zerr  = deflate((z_stream *)http->stream, Z_FINISH);
	  bytes = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;

          if (bytes > 0)
	  {
	    DEBUG_printf(("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes));

	    if (http->data_encoding == HTTP_ENCODING_CHUNKED)
	      http_write_chunk(http, (char *)http->sbuffer, bytes);
	    else
	      http_write(http, (char *)http->sbuffer, bytes);
          }

          ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
          ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
	}
        while (zerr == Z_OK);

        deflateEnd((z_stream *)http->stream);

        free(http->sbuffer);
        free(http->stream);

        http->sbuffer = NULL;
        http->stream  = NULL;

        if (http->wused)
          httpFlushWrite(http);
        break;

    case _HTTP_CODING_INFLATE :
    case _HTTP_CODING_GUNZIP :
        inflateEnd((z_stream *)http->stream);

        free(http->sbuffer);
        free(http->stream);

        http->sbuffer = NULL;
        http->stream  = NULL;
        break;

    default :
        break;
  }

  http->coding = _HTTP_CODING_IDENTITY;
}


http_read_buffered(http_t *http,	/* I - HTTP connection */
                   char   *buffer,	/* I - Buffer */
                   size_t length)	/* I - Maximum bytes to read */
{
  ssize_t	bytes;			/* Bytes read */

  DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT ") used=%d", (void *)http, (void *)buffer, CUPS_LLCAST length, http->used));

  if (http->used > 0)
  {
    if (length > (size_t)http->used)
      bytes = (ssize_t)http->used;
    else
      bytes = (ssize_t)length;

    DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.",
                  (int)bytes));

    memcpy(buffer, http->buffer, (size_t)bytes);
    http->used -= (int)bytes;

    if (http->used > 0)
      memmove(http->buffer, http->buffer + bytes, (size_t)http->used);
  }
  else
    bytes = http_read(http, buffer, length);

  return (bytes);
}


static int finish_line
(struct managesieve_parser *parser, unsigned int count,
	const struct managesieve_arg **args_r)
{
	struct managesieve_arg *arg;
	int ret = array_count(&parser->root_list);

	parser->line_size += parser->cur_pos;
	i_stream_skip(parser->input, parser->cur_pos);
	parser->cur_pos = 0;

	/* fill the missing parameters with NILs */
	while (count > array_count(&parser->root_list)) {
		arg = array_append_space(&parser->root_list);
		arg->type = MANAGESIEVE_ARG_NONE;
	}
	arg = array_append_space(&parser->root_list);
	arg->type = MANAGESIEVE_ARG_EOL;

	*args_r = array_get(&parser->root_list, &count);
	return ret;
}


managesieve_parser_read_string(struct managesieve_parser *parser,
				   const unsigned char *data, size_t data_size)
{
	size_t i;

	/* QUOTED-CHAR        = SAFE-UTF8-CHAR / "\" QUOTED-SPECIALS
	 * quoted             = <"> *QUOTED-CHAR <">
	 *                    ;; limited to 1024 octets between the <">s
	 */

	/* read until we've found non-escaped ", CR or LF */
	for (i = parser->cur_pos; i < data_size; i++) {
		if (data[i] == '"') {

			if ( !uni_utf8_data_is_valid(data+1, i-1) ) {
				parser->error = "Invalid UTF-8 character in quoted-string.";
				return FALSE;
			}

			managesieve_parser_save_arg(parser, data, i);
			i++; /* skip the trailing '"' too */
			break;
		}

		if (data[i] == '\0') {
			parser->error = "NULs not allowed in strings";
			return FALSE;
		}

		if (data[i] == '\\') {
			if (i+1 == data_size) {
				/* known data ends with '\' - leave it to
				   next time as well if it happens to be \" */
				break;
			}

			/* save the first escaped char */
			if (parser->str_first_escape < 0)
				parser->str_first_escape = i;

			/* skip the escaped char */
			i++;

			if ( !IS_QUOTED_SPECIAL(data[i]) ) {
				parser->error =
					"Escaped quoted-string character is not a QUOTED-SPECIAL.";
				return FALSE;
			}

			continue;
		}

		if ( (data[i] & 0x80) == 0 && !IS_SAFE_CHAR(data[i]) ) {
			parser->error = "String contains invalid character.";
			return FALSE;
		}
	}

	parser->cur_pos = i;
	return ( parser->cur_type == ARG_PARSE_NONE );
}


managesieve_parser_literal_end(struct managesieve_parser *parser)
{
	if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) == 0) {
		if (parser->line_size >= parser->max_line_size ||
		    parser->literal_size >
		    	parser->max_line_size - parser->line_size) {
			/* too long string, abort. */
			parser->error = "Literal size too large";
			parser->fatal_error = TRUE;
			return FALSE;
		}
	}

	parser->cur_type = ARG_PARSE_LITERAL_DATA;
	parser->literal_skip_crlf = TRUE;

	parser->cur_pos = 0;
	return TRUE;
}


static void stream_cleanup(h2_mplx *m, h2_stream *stream)
{
    ap_assert(stream->state == H2_SS_CLEANUP);

    if (stream->input) {
        h2_beam_on_consumed(stream->input, NULL, NULL, NULL);
        h2_beam_abort(stream->input);
    }
    if (stream->output) {
        h2_beam_on_produced(stream->output, NULL, NULL);
        h2_beam_leave(stream->output);
    }

    h2_stream_cleanup(stream);

    h2_ihash_remove(m->streams, stream->id);
    h2_iq_remove(m->q, stream->id);
    h2_ififo_remove(m->readyq, stream->id);
    h2_ihash_add(m->shold, stream);

    if (!h2_task_has_started(stream->task) || stream->task->done_done) {
        stream_joined(m, stream);
    }
    else if (stream->task) {
        stream->task->c->aborted = 1;
    }
}


static apr_status_t add_trailer(h2_stream *stream,
                                const char *name, size_t nlen,
                                const char *value, size_t vlen)
{
    conn_rec *c = stream->session->c;
    char *hname, *hvalue;

    if (nlen == 0 || name[0] == ':') {
        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_EINVAL, c,
                      H2_STRM_LOG(APLOGNO(03060), stream,
                      "pseudo header in trailer"));
        return APR_EINVAL;
    }
    if (h2_req_ignore_trailer(name, nlen)) {
        return APR_SUCCESS;
    }
    if (!stream->trailers) {
        stream->trailers = apr_table_make(stream->pool, 5);
    }
    hname = apr_pstrndup(stream->pool, name, nlen);
    hvalue = apr_pstrndup(stream->pool, value, vlen);
    h2_util_camel_case_header(hname, nlen);
    apr_table_mergen(stream->trailers, hname, hvalue);
    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
                  H2_STRM_MSG(stream, "added trailer '%s: %s'"), hname, hvalue);

    return APR_SUCCESS;
}


static apr_bucket *get_first_headers_bucket(apr_bucket_brigade *bb)
{
    if (bb) {
        apr_bucket *b = APR_BRIGADE_FIRST(bb);
        while (b != APR_BRIGADE_SENTINEL(bb)) {
            if (H2_BUCKET_IS_HEADERS(b)) {
                return b;
            }
            b = APR_BUCKET_NEXT(b);
        }
    }
    return NULL;
}


static apr_status_t transit(h2_stream *stream, int new_state)
{
    if (new_state == stream->state) {
        return APR_SUCCESS;
    }
    else if (new_state < 0) {
        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, stream->session->c,
                      H2_STRM_LOG(APLOGNO(03081), stream, "invalid transition"));
        on_state_invalid(stream);
        return APR_EINVAL;
    }

    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c,
                  H2_STRM_MSG(stream, "transit to [%s]"), h2_ss_str(new_state));
    stream->state = new_state;
    switch (new_state) {
        case H2_SS_IDLE:
            break;
        case H2_SS_RSVD_L:
            close_input(stream);
            break;
        case H2_SS_RSVD_R:
            break;
        case H2_SS_OPEN:
            break;
        case H2_SS_CLOSED_L:
            close_output(stream);
            break;
        case H2_SS_CLOSED_R:
            close_input(stream);
            break;
        case H2_SS_CLOSED:
            close_input(stream);
            close_output(stream);
            if (stream->out_buffer) {
                apr_brigade_cleanup(stream->out_buffer);
            }
            break;
        case H2_SS_CLEANUP:
            break;
    }
    on_state_enter(stream);
    return APR_SUCCESS;
}


static int send_loop(h2_proxy_session *session)
{
    while (nghttp2_session_want_write(session->ngh2)) {
        int rv = nghttp2_session_send(session->ngh2);
        if (rv < 0 && nghttp2_is_fatal(rv)) {
            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
                          "h2_proxy_session(%s): write, rv=%d", session->id, rv);
            dispatch_event(session, H2_PROXYS_EV_CONN_ERROR, rv, NULL);
            break;
        }
        return 1;
    }
    return 0;
}


static ssize_t stream_request_data(nghttp2_session *ngh2, int32_t stream_id,
                                   uint8_t *buf, size_t length,
                                   uint32_t *data_flags,
                                   nghttp2_data_source *source, void *user_data)
{
    h2_proxy_stream *stream;
    apr_status_t status = APR_SUCCESS;

    *data_flags = 0;
    stream = nghttp2_session_get_stream_user_data(ngh2, stream_id);
    if (!stream) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(03361)
                     "h2_proxy_stream(NULL): data_read, stream %d not found",
                     stream_id);
        return NGHTTP2_ERR_CALLBACK_FAILURE;
    }

    if (stream->session->check_ping) {
        /* suspend until we hear from the other side */
        stream->waiting_on_ping = 1;
        status = APR_EAGAIN;
    }
    else if (stream->r->expecting_100) {
        /* suspend until the answer comes */
        stream->waiting_on_100 = 1;
        status = APR_EAGAIN;
    }
    else if (APR_BRIGADE_EMPTY(stream->input)) {
        status = ap_get_brigade(stream->r->input_filters, stream->input,
                                AP_MODE_READBYTES, APR_NONBLOCK_READ,
                                H2MAX(APR_BUCKET_BUFF_SIZE, length));
        ap_log_rerror(APLOG_MARK, APLOG_TRACE2, status, stream->r,
                      "h2_proxy_stream(%s-%d): request body read",
                      stream->session->id, stream->id);
    }

    if (status == APR_SUCCESS) {
        ssize_t readlen = 0;
        while (status == APR_SUCCESS
               && (readlen < length)
               && !APR_BRIGADE_EMPTY(stream->input)) {
            apr_bucket* b = APR_BRIGADE_FIRST(stream->input);
            if (APR_BUCKET_IS_METADATA(b)) {
                if (APR_BUCKET_IS_EOS(b)) {
                    *data_flags |= NGHTTP2_DATA_FLAG_EOF;
                }
                else {
                    /* we do nothing more regarding any meta here */
                }
            }
            else {
                const char *bdata = NULL;
                apr_size_t blen = 0;
                status = apr_bucket_read(b, &bdata, &blen, APR_BLOCK_READ);

                if (status == APR_SUCCESS && blen > 0) {
                    ssize_t copylen = H2MIN(length - readlen, blen);
                    memcpy(buf, bdata, copylen);
                    buf += copylen;
                    readlen += copylen;
                    if (copylen < blen) {
                        /* We have data left in the bucket. Split it. */
                        status = apr_bucket_split(b, copylen);
                    }
                }
            }
            apr_bucket_delete(b);
        }

        stream->data_sent += readlen;
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, stream->r, APLOGNO(03468)
                      "h2_proxy_stream(%d): request DATA %ld, %ld"
                      " total, flags=%d", stream->id, (long)readlen, (long)stream->data_sent,
                      (int)*data_flags);
        if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && !apr_is_empty_table(stream->r->trailers_in)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, stream->r, APLOGNO(10179)
                          "h2_proxy_stream(%d): submit trailers", stream->id);
            *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
            submit_trailers(stream);
        }
        return readlen;
    }
    else if (APR_STATUS_IS_EAGAIN(status)) {
        /* suspended stream, needs to be re-awakened */
        ap_log_rerror(APLOG_MARK, APLOG_TRACE2, status, stream->r,
                      "h2_proxy_stream(%s-%d): suspending",
                      stream->session->id, stream_id);
        stream->suspended = 1;
        h2_proxy_iq_add(stream->session->suspended, stream->id, NULL, NULL);
        return NGHTTP2_ERR_DEFERRED;
    }
    else {
        nghttp2_submit_rst_stream(ngh2, NGHTTP2_FLAG_NONE,
                                  stream_id, NGHTTP2_STREAM_CLOSED);
        return NGHTTP2_ERR_STREAM_CLOSING;
    }
}


apr_status_t h2_session_process(h2_session *session, int async)
{
    apr_status_t status = APR_SUCCESS;
    conn_rec *c = session->c;
    int rv, mpm_state, trace = APLOGctrace3(c);
    apr_time_t now;

    if (trace) {
        ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c,
                      H2_SSSN_MSG(session, "process start, async=%d"), async);
    }

    while (session->state != H2_SESSION_ST_DONE) {
        now = apr_time_now();
        session->have_read = session->have_written = 0;

        if (session->local.accepting
            && !ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) {
            if (mpm_state == AP_MPMQ_STOPPING) {
                dispatch_event(session, H2_SESSION_EV_MPM_STOPPING, 0, NULL);
            }
        }

        session->status[0] = '\0';

        switch (session->state) {
            case H2_SESSION_ST_INIT:
                ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
                if (!h2_is_acceptable_connection(c, session->r, 1)) {
                    update_child_status(session, SERVER_BUSY_READ,
                                        "inadequate security");
                    h2_session_shutdown(session,
                                        NGHTTP2_INADEQUATE_SECURITY, NULL, 1);
                }
                else {
                    update_child_status(session, SERVER_BUSY_READ, "init");
                    status = h2_session_start(session, &rv);
                    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
                                  H2_SSSN_LOG(APLOGNO(03079), session,
                                  "started on %s:%d"),
                                  session->s->server_hostname,
                                  c->local_addr->port);
                    if (status != APR_SUCCESS) {
                        dispatch_event(session,
                                       H2_SESSION_EV_CONN_ERROR, 0, NULL);
                    }
                    dispatch_event(session, H2_SESSION_EV_INIT, 0, NULL);
                }
                break;

            case H2_SESSION_ST_IDLE:
                if (session->idle_until && (apr_time_now() + session->idle_delay) > session->idle_until) {
                    ap_log_cerror( APLOG_MARK, APLOG_TRACE1, status, c,
                                  H2_SSSN_MSG(session, "idle, timeout reached, closing"));
                    if (session->idle_delay) {
                        apr_table_setn(session->c->notes, "short-lingering-close", "1");
                    }
                    dispatch_event(session, H2_SESSION_EV_CONN_TIMEOUT, 0, "timeout");
                    goto out;
                }

                if (session->idle_delay) {
                    /* we are less interested in spending time on this connection */
                    ap_log_cerror( APLOG_MARK, APLOG_TRACE2, status, c,
                                  H2_SSSN_MSG(session, "session is idle (%ld ms), idle wait %ld sec left"),
                                  (long)apr_time_as_msec(session->idle_delay),
                                  (long)apr_time_sec(session->idle_until - now));
                    apr_sleep(session->idle_delay);
                    session->idle_delay = 0;
                }

                h2_conn_io_flush(&session->io);
                if (async && !session->r && (now > session->idle_sync_until)) {
                    if (trace) {
                        ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
                                      H2_SSSN_MSG(session,
                                      "nonblock read, %d streams open"),
                                      session->open_streams);
                    }
                    status = h2_session_read(session, 0);

                    if (status == APR_SUCCESS) {
                        session->have_read = 1;
                    }
                    else if (APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) {
                        status = h2_mplx_idle(session->mplx);
                        if (status == APR_EAGAIN) {
                            break;
                        }
                        else if (status != APR_SUCCESS) {
                            dispatch_event(session, H2_SESSION_EV_CONN_ERROR,
                                           H2_ERR_ENHANCE_YOUR_CALM, "less is more");
                        }
                        status = APR_EAGAIN;
                        goto out;
                    }
                    else {
                        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
                                      H2_SSSN_LOG(APLOGNO(03403), session,
                                      "no data, error"));
                        dispatch_event(session,
                                       H2_SESSION_EV_CONN_ERROR, 0, "timeout");
                    }
                }
                else {
                    /* make certain, we send everything before we idle */
                    if (trace) {
                        ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
                                      H2_SSSN_MSG(session,
                                      "sync, stutter 1-sec, %d streams open"),
                                      session->open_streams);
                    }
                    /* We wait in smaller increments, using a 1 second timeout.
                     * That gives us the chance to check for MPMQ_STOPPING often.
                     */
                    status = h2_mplx_idle(session->mplx);
                    if (status == APR_EAGAIN) {
                        break;
                    }
                    else if (status != APR_SUCCESS) {
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR,
                                       H2_ERR_ENHANCE_YOUR_CALM, "less is more");
                    }
                    h2_filter_cin_timeout_set(session->cin, apr_time_from_sec(1));
                    status = h2_session_read(session, 1);
                    if (status == APR_SUCCESS) {
                        session->have_read = 1;
                    }
                    else if (status == APR_EAGAIN) {
                        /* nothing to read */
                    }
                    else if (APR_STATUS_IS_TIMEUP(status)) {
                        /* continue reading handling */
                    }
                    else if (APR_STATUS_IS_ECONNABORTED(status)
                             || APR_STATUS_IS_ECONNRESET(status)
                             || APR_STATUS_IS_EOF(status)
                             || APR_STATUS_IS_EBADF(status)) {
                        ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c,
                                      H2_SSSN_MSG(session, "input gone"));
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
                    }
                    else {
                        ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c,
                                      H2_SSSN_MSG(session,
                                      "(1 sec timeout) read failed"));
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, "error");
                    }
                }
                if (nghttp2_session_want_write(session->ngh2)) {
                    ap_update_child_status(session->c->sbh, SERVER_BUSY_WRITE, NULL);
                    status = h2_session_send(session);
                    if (status == APR_SUCCESS) {
                        status = h2_conn_io_flush(&session->io);
                    }
                    if (status != APR_SUCCESS) {
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR,
                                       H2_ERR_INTERNAL_ERROR, "writing");
                        break;
                    }
                }
                break;

            case H2_SESSION_ST_BUSY:
                if (nghttp2_session_want_read(session->ngh2)) {
                    ap_update_child_status(session->c->sbh, SERVER_BUSY_READ, NULL);
                    h2_filter_cin_timeout_set(session->cin, session->s->timeout);
                    status = h2_session_read(session, 0);
                    if (status == APR_SUCCESS) {
                        session->have_read = 1;
                    }
                    else if (status == APR_EAGAIN) {
                        /* nothing to read */
                    }
                    else if (APR_STATUS_IS_TIMEUP(status)) {
                        dispatch_event(session, H2_SESSION_EV_CONN_TIMEOUT, 0, NULL);
                        break;
                    }
                    else {
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
                    }
                }

                status = dispatch_master(session);
                if (status != APR_SUCCESS && status != APR_EAGAIN) {
                    break;
                }

                if (nghttp2_session_want_write(session->ngh2)) {
                    ap_update_child_status(session->c->sbh, SERVER_BUSY_WRITE, NULL);
                    status = h2_session_send(session);
                    if (status == APR_SUCCESS) {
                        status = h2_conn_io_flush(&session->io);
                    }
                    if (status != APR_SUCCESS) {
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR,
                                       H2_ERR_INTERNAL_ERROR, "writing");
                        break;
                    }
                }

                if (session->have_read || session->have_written) {
                    if (session->wait_us) {
                        session->wait_us = 0;
                    }
                }
                else if (!nghttp2_session_want_write(session->ngh2)) {
                    dispatch_event(session, H2_SESSION_EV_NO_IO, 0, NULL);
                }
                break;

            case H2_SESSION_ST_WAIT:
                if (session->wait_us <= 0) {
                    session->wait_us = 10;
                    if (h2_conn_io_flush(&session->io) != APR_SUCCESS) {
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
                        break;
                    }
                }
                else {
                    /* repeating, increase timer for graceful backoff */
                    session->wait_us = H2MIN(session->wait_us*2, MAX_WAIT_MICROS);
                }

                if (trace) {
                    ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c,
                                  "h2_session: wait for data, %ld micros",
                                  (long)session->wait_us);
                }
                status = h2_mplx_out_trywait(session->mplx, session->wait_us,
                                             session->iowait);
                if (status == APR_SUCCESS) {
                    session->wait_us = 0;
                        dispatch_event(session, H2_SESSION_EV_STREAM_CHANGE, 0, NULL);
                }
                else if (APR_STATUS_IS_TIMEUP(status)) {
                    /* go back to checking all inputs again */
                    transit(session, "wait cycle", session->local.shutdown?
                            H2_SESSION_ST_DONE : H2_SESSION_ST_BUSY);
                }
                else if (APR_STATUS_IS_ECONNRESET(status)
                         || APR_STATUS_IS_ECONNABORTED(status)) {
                    dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
                }
                else {
                    ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, c,
                                  H2_SSSN_LOG(APLOGNO(03404), session,
                                  "waiting on conditional"));
                    h2_session_shutdown(session, H2_ERR_INTERNAL_ERROR,
                                        "cond wait error", 0);
                }
                break;

            default:
                ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c,
                              H2_SSSN_LOG(APLOGNO(03080), session,
                              "unknown state"));
                dispatch_event(session, H2_SESSION_EV_PROTO_ERROR, 0, NULL);
                break;
        }

        if (!nghttp2_session_want_read(session->ngh2)
                 && !nghttp2_session_want_write(session->ngh2)) {
            dispatch_event(session, H2_SESSION_EV_NGH2_DONE, 0, NULL);
        }
        if (session->reprioritize) {
            h2_mplx_reprioritize(session->mplx, stream_pri_cmp, session);
            session->reprioritize = 0;
        }
    }

out:
    if (trace) {
        ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c,
                      H2_SSSN_MSG(session, "process returns"));
    }

    if ((session->state != H2_SESSION_ST_DONE)
        && (APR_STATUS_IS_EOF(status)
            || APR_STATUS_IS_ECONNRESET(status)
            || APR_STATUS_IS_ECONNABORTED(status))) {
        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
    }

    return (session->state == H2_SESSION_ST_DONE)? APR_EOF : APR_SUCCESS;
}


static void ev_proto_error(h2_proxy_session *session, int arg, const char *msg)
{
    switch (session->state) {
        case H2_PROXYS_ST_DONE:
        case H2_PROXYS_ST_LOCAL_SHUTDOWN:
            /* just leave */
            transit(session, "proto error", H2_PROXYS_ST_DONE);
            break;

        default:
            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
                          "h2_proxy_session(%s): proto error -> shutdown", session->id);
            session_shutdown(session, arg, msg);
            break;
    }
}


static int before_frame_send(nghttp2_session *ngh2,
                             const nghttp2_frame *frame, void *user_data)
{
    h2_proxy_session *session = user_data;
    if (APLOGcdebug(session->c)) {
        char buffer[256];

        h2_proxy_util_frame_print(frame, buffer, sizeof(buffer)/sizeof(buffer[0]));
        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03343)
                      "h2_proxy_session(%s): sent FRAME[%s]",
                      session->id, buffer);
    }
    return 0;
}


static apr_status_t open_stream(h2_proxy_session *session, const char *url,
                                request_rec *r, int standalone,
                                h2_proxy_stream **pstream)
{
    h2_proxy_stream *stream;
    apr_uri_t puri;
    const char *authority, *scheme, *path;
    apr_status_t status;
    proxy_dir_conf *dconf;

    stream = apr_pcalloc(r->pool, sizeof(*stream));

    stream->pool = r->pool;
    stream->url = url;
    stream->r = r;
    stream->standalone = standalone;
    stream->session = session;
    stream->state = H2_STREAM_ST_IDLE;

    stream->input = apr_brigade_create(stream->pool, session->c->bucket_alloc);
    stream->output = apr_brigade_create(stream->pool, session->c->bucket_alloc);

    stream->req = h2_proxy_req_create(1, stream->pool, 0);

    status = apr_uri_parse(stream->pool, url, &puri);
    if (status != APR_SUCCESS)
        return status;

    scheme = (strcmp(puri.scheme, "h2")? "http" : "https");

    dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
    if (dconf->preserve_host) {
        authority = r->hostname;
    }
    else {
        authority = puri.hostname;
        if (!ap_strchr_c(authority, ':') && puri.port
            && apr_uri_port_of_scheme(scheme) != puri.port) {
            /* port info missing and port is not default for scheme: append */
            authority = apr_psprintf(stream->pool, "%s:%d", authority, puri.port);
        }
    }

    /* we need this for mapping relative uris in headers ("Link") back
     * to local uris */
    stream->real_server_uri = apr_psprintf(stream->pool, "%s://%s", scheme, authority);
    stream->p_server_uri = apr_psprintf(stream->pool, "%s://%s", puri.scheme, authority);
    path = apr_uri_unparse(stream->pool, &puri, APR_URI_UNP_OMITSITEPART);

    h2_proxy_req_make(stream->req, stream->pool, r->method, scheme,
                authority, path, r->headers_in);

    if (dconf->add_forwarded_headers) {
        if (PROXYREQ_REVERSE == r->proxyreq) {
            const char *buf;

            /* Add X-Forwarded-For: so that the upstream has a chance to
             * determine, where the original request came from.
             */
            apr_table_mergen(stream->req->headers, "X-Forwarded-For",
                             r->useragent_ip);

            /* Add X-Forwarded-Host: so that upstream knows what the
             * original request hostname was.
             */
            if ((buf = apr_table_get(r->headers_in, "Host"))) {
                apr_table_mergen(stream->req->headers, "X-Forwarded-Host", buf);
            }

            /* Add X-Forwarded-Server: so that upstream knows what the
             * name of this proxy server is (if there are more than one)
             * XXX: This duplicates Via: - do we strictly need it?
             */
            apr_table_mergen(stream->req->headers, "X-Forwarded-Server",
                             r->server->server_hostname);
        }
    }

    /* Tuck away all already existing cookies */
    stream->saves = apr_table_make(r->pool, 2);
    apr_table_do(add_header, stream->saves, r->headers_out, "Set-Cookie", NULL);

    *pstream = stream;

    return APR_SUCCESS;
}


static apr_status_t unschedule_slow_tasks(h2_mplx *m)
{
    h2_task *task;
    apr_status_t rv;

    /* Try to get rid of streams that occupy workers. Look for safe requests
     * that are repeatable. If none found, fail the connection.
     */
    while (APR_EAGAIN == (rv = assess_task_to_throttle(&task, m))) {
        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
                      "h2_mplx(%s): unschedule, resetting task for redo later",
                      task->id);
        task->redo = 1;
        h2_task_rst(task, H2_ERR_CANCEL);
    }
    return rv;
}


int h2_mplx_awaits_data(h2_mplx *m)
{
    int waiting = 1;

    H2_MPLX_ENTER_ALWAYS(m);

    if (h2_ihash_empty(m->streams)) {
        waiting = 0;
    }
    else if (!m->tasks_active && !h2_ififo_count(m->readyq) && h2_iq_empty(m->q)) {
        waiting = 0;
    }

    H2_MPLX_LEAVE(m);
    return waiting;
}


static int on_frame_send(h2_stream_state_t state, int frame_type)
{
    return on_frame(state, frame_type, trans_on_send, H2_ALEN(trans_on_send));
}


static void on_stream_state_enter(void *ctx, h2_stream *stream)
{
    h2_session *session = ctx;
    /* stream entered a new state */
    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
                  H2_STRM_MSG(stream, "entered state"));
    switch (stream->state) {
        case H2_SS_IDLE: /* stream was created */
            ++session->open_streams;
            if (H2_STREAM_CLIENT_INITIATED(stream->id)) {
                ++session->remote.emitted_count;
                if (stream->id > session->remote.emitted_max) {
                    session->remote.emitted_max = stream->id;
                    session->local.accepted_max = stream->id;
                }
            }
            else {
                if (stream->id > session->local.emitted_max) {
                    ++session->local.emitted_count;
                    session->remote.emitted_max = stream->id;
                }
            }
            break;
        case H2_SS_OPEN: /* stream has request headers */
        case H2_SS_RSVD_L: /* stream has request headers */
            ev_stream_open(session, stream);
            break;
        case H2_SS_CLOSED_L: /* stream output was closed */
            break;
        case H2_SS_CLOSED_R: /* stream input was closed */
            break;
        case H2_SS_CLOSED: /* stream in+out were closed */
            --session->open_streams;
            ev_stream_closed(session, stream);
            break;
        case H2_SS_CLEANUP:
            nghttp2_session_set_stream_user_data(session->ngh2, stream->id, NULL);
            h2_mplx_stream_cleanup(session->mplx, stream);
            break;
        default:
            break;
    }
    dispatch_event(session, H2_SESSION_EV_STREAM_CHANGE, 0, "stream state change");
}


static apr_status_t close_output(h2_stream *stream)
{
    if (!stream->output || h2_beam_is_closed(stream->output)) {
        return APR_SUCCESS;
    }
    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c,
                  H2_STRM_MSG(stream, "closing output"));
    return h2_beam_leave(stream->output);
}


static int uac_mixer_unit_get_channels(struct mixer_build *state,
				       struct uac_mixer_unit_descriptor *desc)
{
	int mu_channels;
	void *c;

	if (desc->bLength < sizeof(*desc))
		return -EINVAL;
	if (!desc->bNrInPins)
		return -EINVAL;
	if (desc->bLength < sizeof(*desc) + desc->bNrInPins)
		return -EINVAL;

	switch (state->mixer->protocol) {
	case UAC_VERSION_1:
	case UAC_VERSION_2:
	default:
		if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 1)
			return 0; /* no bmControls -> skip */
		mu_channels = uac_mixer_unit_bNrChannels(desc);
		break;
	case UAC_VERSION_3:
		mu_channels = get_cluster_channels_v3(state,
				uac3_mixer_unit_wClusterDescrID(desc));
		break;
	}

	if (!mu_channels)
		return 0;

	c = uac_mixer_unit_bmControls(desc, state->mixer->protocol);
	if (c - (void *)desc + (mu_channels - 1) / 8 >= desc->bLength)
		return 0; /* no bmControls -> skip */

	return mu_channels;
}


static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	struct usb_mixer_elem_info *cval = kcontrol->private_data;
	struct snd_usb_audio *chip = cval->head.mixer->chip;
	int idx = 0, validx, ret, val;

	validx = cval->control << 8 | 0;

	ret = snd_usb_lock_shutdown(chip) ? -EIO : 0;
	if (ret)
		goto error;

	idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
	if (cval->head.mixer->protocol == UAC_VERSION_2) {
		struct uac2_connectors_ctl_blk uac2_conn;

		ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR,
				      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
				      validx, idx, &uac2_conn, sizeof(uac2_conn));
		val = !!uac2_conn.bNrChannels;
	} else { /* UAC_VERSION_3 */
		struct uac3_insertion_ctl_blk uac3_conn;

		ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR,
				      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
				      validx, idx, &uac3_conn, sizeof(uac3_conn));
		val = !!uac3_conn.bmConInserted;
	}

	snd_usb_unlock_shutdown(chip);

	if (ret < 0) {
error:
		usb_audio_err(chip,
			"cannot get connectors status: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
			UAC_GET_CUR, validx, idx, cval->val_type);
		return ret;
	}

	ucontrol->value.integer.value[0] = val;
	return 0;
}


static int create_keep_iface_ctl(struct usb_mixer_interface *mixer)
{
	struct snd_kcontrol *kctl = snd_ctl_new1(&keep_iface_ctl, mixer);

	/* need only one control per card */
	if (snd_ctl_find_id(mixer->chip->card, &kctl->id)) {
		snd_ctl_free_one(kctl);
		return 0;
	}

	return snd_ctl_add(mixer->chip->card, kctl);
}


static int vidioc_g_tuner(struct file *file, void *priv,
		struct v4l2_tuner *v)
{
	struct raremono_device *radio = video_drvdata(file);
	int ret;

	if (v->index > 0)
		return -EINVAL;

	strscpy(v->name, "AM/FM/SW", sizeof(v->name));
	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
		V4L2_TUNER_CAP_FREQ_BANDS;
	v->rangelow = AM_FREQ_RANGE_LOW * 16;
	v->rangehigh = FM_FREQ_RANGE_HIGH * 16;
	v->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
	v->audmode = (radio->curfreq < FM_FREQ_RANGE_LOW) ?
		V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO;
	memset(radio->buffer, 1, BUFFER_LENGTH);
	ret = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
			1, 0xa1, 0x030d, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);

	if (ret < 0) {
		dev_warn(radio->v4l2_dev.dev, "%s failed (%d)\n", __func__, ret);
		return ret;
	}
	v->signal = ((radio->buffer[1] & 0xf) << 8 | radio->buffer[2]) << 4;
	return 0;
}


static int raremono_cmd_main(struct raremono_device *radio, unsigned band, unsigned freq)
{
	unsigned band_offset;
	int ret;

	switch (band) {
	case BAND_FM:
		band_offset = 1;
		freq /= 10;
		break;
	case BAND_AM:
		band_offset = 0;
		break;
	default:
		band_offset = 2;
		break;
	}
	radio->buffer[0] = 0x04 + band_offset;
	radio->buffer[1] = freq >> 8;
	radio->buffer[2] = freq & 0xff;

	ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
			HID_REQ_SET_REPORT,
			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
			0x0300 + radio->buffer[0], 2,
			radio->buffer, 3, USB_TIMEOUT);

	if (ret < 0) {
		dev_warn(radio->v4l2_dev.dev, "%s failed (%d)\n", __func__, ret);
		return ret;
	}
	radio->curfreq = (band == BAND_FM) ? freq * 10 : freq;
	return 0;
}


static int vidioc_querycap(struct file *file, void *priv,
					struct v4l2_capability *v)
{
	struct raremono_device *radio = video_drvdata(file);

	strscpy(v->driver, "radio-raremono", sizeof(v->driver));
	strscpy(v->card, "Thanko's Raremono", sizeof(v->card));
	usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
	return 0;
}


init_xfs_fs(void)
{
	int			error;

	xfs_check_ondisk_structs();

	printk(KERN_INFO XFS_VERSION_STRING " with "
			 XFS_BUILD_OPTIONS " enabled\n");

	xfs_extent_free_init_defer_op();
	xfs_rmap_update_init_defer_op();
	xfs_refcount_update_init_defer_op();
	xfs_bmap_update_init_defer_op();

	xfs_dir_startup();

	error = xfs_init_zones();
	if (error)
		goto out;

	error = xfs_init_workqueues();
	if (error)
		goto out_destroy_zones;

	error = xfs_mru_cache_init();
	if (error)
		goto out_destroy_wq;

	error = xfs_buf_init();
	if (error)
		goto out_mru_cache_uninit;

	error = xfs_init_procfs();
	if (error)
		goto out_buf_terminate;

	error = xfs_sysctl_register();
	if (error)
		goto out_cleanup_procfs;

	xfs_kset = kset_create_and_add("xfs", NULL, fs_kobj);
	if (!xfs_kset) {
		error = -ENOMEM;
		goto out_sysctl_unregister;
	}

	xfsstats.xs_kobj.kobject.kset = xfs_kset;

	xfsstats.xs_stats = alloc_percpu(struct xfsstats);
	if (!xfsstats.xs_stats) {
		error = -ENOMEM;
		goto out_kset_unregister;
	}

	error = xfs_sysfs_init(&xfsstats.xs_kobj, &xfs_stats_ktype, NULL,
			       "stats");
	if (error)
		goto out_free_stats;

#ifdef DEBUG
	xfs_dbg_kobj.kobject.kset = xfs_kset;
	error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug");
	if (error)
		goto out_remove_stats_kobj;
#endif

	error = xfs_qm_init();
	if (error)
		goto out_remove_dbg_kobj;

	error = register_filesystem(&xfs_fs_type);
	if (error)
		goto out_qm_exit;
	return 0;

 out_qm_exit:
	xfs_qm_exit();
 out_remove_dbg_kobj:
#ifdef DEBUG
	xfs_sysfs_del(&xfs_dbg_kobj);
 out_remove_stats_kobj:
#endif
	xfs_sysfs_del(&xfsstats.xs_kobj);
 out_free_stats:
	free_percpu(xfsstats.xs_stats);
 out_kset_unregister:
	kset_unregister(xfs_kset);
 out_sysctl_unregister:
	xfs_sysctl_unregister();
 out_cleanup_procfs:
	xfs_cleanup_procfs();
 out_buf_terminate:
	xfs_buf_terminate();
 out_mru_cache_uninit:
	xfs_mru_cache_uninit();
 out_destroy_wq:
	xfs_destroy_workqueues();
 out_destroy_zones:
	xfs_destroy_zones();
 out:
	return error;
}


xfs_fs_unfreeze(
	struct super_block	*sb)
{
	struct xfs_mount	*mp = XFS_M(sb);

	xfs_restore_resvblks(mp);
	xfs_log_work_queue(mp);
	xfs_icache_enable_reclaim(mp);
	return 0;
}


xfs_fs_remount(
	struct super_block	*sb,
	int			*flags,
	char			*options)
{
	struct xfs_mount	*mp = XFS_M(sb);
	xfs_sb_t		*sbp = &mp->m_sb;
	substring_t		args[MAX_OPT_ARGS];
	char			*p;
	int			error;

	/* First, check for complete junk; i.e. invalid options */
	error = xfs_test_remount_options(sb, options);
	if (error)
		return error;

	sync_filesystem(sb);
	while ((p = strsep(&options, ",")) != NULL) {
		int token;

		if (!*p)
			continue;

		token = match_token(p, tokens, args);
		switch (token) {
		case Opt_barrier:
			xfs_warn(mp, "%s option is deprecated, ignoring.", p);
			mp->m_flags |= XFS_MOUNT_BARRIER;
			break;
		case Opt_nobarrier:
			xfs_warn(mp, "%s option is deprecated, ignoring.", p);
			mp->m_flags &= ~XFS_MOUNT_BARRIER;
			break;
		case Opt_inode64:
			mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
			mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount);
			break;
		case Opt_inode32:
			mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
			mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount);
			break;
		default:
			/*
			 * Logically we would return an error here to prevent
			 * users from believing they might have changed
			 * mount options using remount which can't be changed.
			 *
			 * But unfortunately mount(8) adds all options from
			 * mtab and fstab to the mount arguments in some cases
			 * so we can't blindly reject options, but have to
			 * check for each specified option if it actually
			 * differs from the currently set option and only
			 * reject it if that's the case.
			 *
			 * Until that is implemented we return success for
			 * every remount request, and silently ignore all
			 * options that we can't actually change.
			 */
#if 0
			xfs_info(mp,
		"mount option \"%s\" not supported for remount", p);
			return -EINVAL;
#else
			break;
#endif
		}
	}

	/* ro -> rw */
	if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & SB_RDONLY)) {
		if (mp->m_flags & XFS_MOUNT_NORECOVERY) {
			xfs_warn(mp,
		"ro->rw transition prohibited on norecovery mount");
			return -EINVAL;
		}

		if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
		    xfs_sb_has_ro_compat_feature(sbp,
					XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
			xfs_warn(mp,
"ro->rw transition prohibited on unknown (0x%x) ro-compat filesystem",
				(sbp->sb_features_ro_compat &
					XFS_SB_FEAT_RO_COMPAT_UNKNOWN));
			return -EINVAL;
		}

		mp->m_flags &= ~XFS_MOUNT_RDONLY;

		/*
		 * If this is the first remount to writeable state we
		 * might have some superblock changes to update.
		 */
		if (mp->m_update_sb) {
			error = xfs_sync_sb(mp, false);
			if (error) {
				xfs_warn(mp, "failed to write sb changes");
				return error;
			}
			mp->m_update_sb = false;
		}

		/*
		 * Fill out the reserve pool if it is empty. Use the stashed
		 * value if it is non-zero, otherwise go with the default.
		 */
		xfs_restore_resvblks(mp);
		xfs_log_work_queue(mp);

		/* Recover any CoW blocks that never got remapped. */
		error = xfs_reflink_recover_cow(mp);
		if (error) {
			xfs_err(mp,
	"Error %d recovering leftover CoW allocations.", error);
			xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
			return error;
		}
		xfs_icache_enable_reclaim(mp);

		/* Create the per-AG metadata reservation pool .*/
		error = xfs_fs_reserve_ag_blocks(mp);
		if (error && error != -ENOSPC)
			return error;
	}

	/* rw -> ro */
	if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & SB_RDONLY)) {
		/*
		 * Cancel background eofb scanning so it cannot race with the
		 * final log force+buftarg wait and deadlock the remount.
		 */
		xfs_icache_disable_reclaim(mp);

		/* Get rid of any leftover CoW reservations... */
		error = xfs_icache_free_cowblocks(mp, NULL);
		if (error) {
			xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
			return error;
		}

		/* Free the per-AG metadata reservation pool. */
		error = xfs_fs_unreserve_ag_blocks(mp);
		if (error) {
			xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
			return error;
		}

		/*
		 * Before we sync the metadata, we need to free up the reserve
		 * block pool so that the used block count in the superblock on
		 * disk is correct at the end of the remount. Stash the current
		 * reserve pool size so that if we get remounted rw, we can
		 * return it to the same size.
		 */
		xfs_save_resvblks(mp);

		xfs_quiesce_attr(mp);
		mp->m_flags |= XFS_MOUNT_RDONLY;
	}

	return 0;
}


xfs_destroy_percpu_counters(
	struct xfs_mount	*mp)
{
	percpu_counter_destroy(&mp->m_icount);
	percpu_counter_destroy(&mp->m_ifree);
	percpu_counter_destroy(&mp->m_fdblocks);
}


xfs_fs_show_options(
	struct seq_file		*m,
	struct dentry		*root)
{
	return xfs_showargs(XFS_M(root->d_sb), m);
}


static int ath6kl_usb_ctrl_msg_exchange(struct ath6kl_usb *ar_usb,
				     u8 req_val, u8 *req_buf, u32 req_len,
				     u8 resp_val, u8 *resp_buf, u32 *resp_len)
{
	int ret;

	/* send command */
	ret = ath6kl_usb_submit_ctrl_out(ar_usb, req_val, 0, 0,
					 req_buf, req_len);

	if (ret != 0)
		return ret;

	if (resp_buf == NULL) {
		/* no expected response */
		return ret;
	}

	/* get response */
	ret = ath6kl_usb_submit_ctrl_in(ar_usb, resp_val, 0, 0,
					resp_buf, *resp_len);

	return ret;
}


static void ath6kl_usb_io_comp_work(struct work_struct *work)
{
	struct ath6kl_usb_pipe *pipe = container_of(work,
						    struct ath6kl_usb_pipe,
						    io_complete_work);
	struct ath6kl_usb *ar_usb;
	struct sk_buff *skb;

	ar_usb = pipe->ar_usb;

	while ((skb = skb_dequeue(&pipe->io_comp_queue))) {
		if (pipe->flags & ATH6KL_USB_PIPE_FLAG_TX) {
			ath6kl_dbg(ATH6KL_DBG_USB_BULK,
				   "ath6kl usb xmit callback buf:0x%p\n", skb);
			ath6kl_core_tx_complete(ar_usb->ar, skb);
		} else {
			ath6kl_dbg(ATH6KL_DBG_USB_BULK,
				   "ath6kl usb recv callback buf:0x%p\n", skb);
			ath6kl_core_rx_complete(ar_usb->ar, skb,
						pipe->logical_pipe_num);
		}
	}
}


static void ath6kl_usb_free_pipe_resources(struct ath6kl_usb_pipe *pipe)
{
	struct ath6kl_urb_context *urb_context;

	if (pipe->ar_usb == NULL) {
		/* nothing allocated for this pipe */
		return;
	}

	ath6kl_dbg(ATH6KL_DBG_USB,
		   "ath6kl usb: free resources lpipe:%d"
		   "hpipe:0x%X urbs:%d avail:%d\n",
		   pipe->logical_pipe_num, pipe->usb_pipe_handle,
		   pipe->urb_alloc, pipe->urb_cnt);

	if (pipe->urb_alloc != pipe->urb_cnt) {
		ath6kl_dbg(ATH6KL_DBG_USB,
			   "ath6kl usb: urb leak! lpipe:%d"
			   "hpipe:0x%X urbs:%d avail:%d\n",
			   pipe->logical_pipe_num, pipe->usb_pipe_handle,
			   pipe->urb_alloc, pipe->urb_cnt);
	}

	while (true) {
		urb_context = ath6kl_usb_alloc_urb_from_pipe(pipe);
		if (urb_context == NULL)
			break;
		kfree(urb_context);
	}
}


static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe,
					struct ath6kl_urb_context *urb_context)
{
	unsigned long flags;

	/* bail if this pipe is not initialized */
	if (!pipe->ar_usb)
		return;

	spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
	pipe->urb_cnt++;

	list_add(&urb_context->link, &pipe->urb_list_head);
	spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags);
}


static void ath6kl_usb_recv_complete(struct urb *urb)
{
	struct ath6kl_urb_context *urb_context = urb->context;
	struct ath6kl_usb_pipe *pipe = urb_context->pipe;
	struct sk_buff *skb = NULL;
	int status = 0;

	ath6kl_dbg(ATH6KL_DBG_USB_BULK,
		   "%s: recv pipe: %d, stat:%d, len:%d urb:0x%p\n", __func__,
		   pipe->logical_pipe_num, urb->status, urb->actual_length,
		   urb);

	if (urb->status != 0) {
		status = -EIO;
		switch (urb->status) {
		case -ECONNRESET:
		case -ENOENT:
		case -ESHUTDOWN:
			/*
			 * no need to spew these errors when device
			 * removed or urb killed due to driver shutdown
			 */
			status = -ECANCELED;
			break;
		default:
			ath6kl_dbg(ATH6KL_DBG_USB_BULK,
				   "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n",
				   __func__, pipe->logical_pipe_num,
				   pipe->ep_address, urb->status);
			break;
		}
		goto cleanup_recv_urb;
	}

	if (urb->actual_length == 0)
		goto cleanup_recv_urb;

	skb = urb_context->skb;

	/* we are going to pass it up */
	urb_context->skb = NULL;
	skb_put(skb, urb->actual_length);

	/* note: queue implements a lock */
	skb_queue_tail(&pipe->io_comp_queue, skb);
	schedule_work(&pipe->io_complete_work);

cleanup_recv_urb:
	ath6kl_usb_cleanup_recv_urb(urb_context);

	if (status == 0 &&
	    pipe->urb_cnt >= pipe->urb_cnt_thresh) {
		/* our free urbs are piling up, post more transfers */
		ath6kl_usb_post_recv_transfers(pipe, ATH6KL_USB_RX_BUFFER_SIZE);
	}
}


ath10k_usb_alloc_urb_from_pipe(struct ath10k_usb_pipe *pipe)
{
	struct ath10k_urb_context *urb_context = NULL;
	unsigned long flags;

	/* bail if this pipe is not initialized */
	if (!pipe->ar_usb)
		return NULL;

	spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
	if (!list_empty(&pipe->urb_list_head)) {
		urb_context = list_first_entry(&pipe->urb_list_head,
					       struct ath10k_urb_context, link);
		list_del(&urb_context->link);
		pipe->urb_cnt--;
	}
	spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags);

	return urb_context;
}


int dvb_usb_device_init(struct usb_interface *intf,
			struct dvb_usb_device_properties *props,
			struct module *owner, struct dvb_usb_device **du,
			short *adapter_nums)
{
	struct usb_device *udev = interface_to_usbdev(intf);
	struct dvb_usb_device *d = NULL;
	struct dvb_usb_device_description *desc = NULL;

	int ret = -ENOMEM, cold = 0;

	if (du != NULL)
		*du = NULL;

	if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) {
		deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
		return -ENODEV;
	}

	if (cold) {
		info("found a '%s' in cold state, will try to load a firmware", desc->name);
		ret = dvb_usb_download_firmware(udev, props);
		if (!props->no_reconnect || ret != 0)
			return ret;
	}

	info("found a '%s' in warm state.", desc->name);
	d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
	if (d == NULL) {
		err("no memory for 'struct dvb_usb_device'");
		return -ENOMEM;
	}

	d->udev = udev;
	memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
	d->desc = desc;
	d->owner = owner;

	usb_set_intfdata(intf, d);

	if (du != NULL)
		*du = d;

	ret = dvb_usb_init(d, adapter_nums);

	if (ret == 0)
		info("%s successfully initialized and connected.", desc->name);
	else
		info("%s error while loading driver (%d)", desc->name, ret);
	return ret;
}


int snd_card_new(struct device *parent, int idx, const char *xid,
		    struct module *module, int extra_size,
		    struct snd_card **card_ret)
{
	struct snd_card *card;
	int err;

	if (snd_BUG_ON(!card_ret))
		return -EINVAL;
	*card_ret = NULL;

	if (extra_size < 0)
		extra_size = 0;
	card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
	if (!card)
		return -ENOMEM;
	if (extra_size > 0)
		card->private_data = (char *)card + sizeof(struct snd_card);
	if (xid)
		strlcpy(card->id, xid, sizeof(card->id));
	err = 0;
	mutex_lock(&snd_card_mutex);
	if (idx < 0) /* first check the matching module-name slot */
		idx = get_slot_from_bitmask(idx, module_slot_match, module);
	if (idx < 0) /* if not matched, assign an empty slot */
		idx = get_slot_from_bitmask(idx, check_empty_slot, module);
	if (idx < 0)
		err = -ENODEV;
	else if (idx < snd_ecards_limit) {
		if (test_bit(idx, snd_cards_lock))
			err = -EBUSY;	/* invalid */
	} else if (idx >= SNDRV_CARDS)
		err = -ENODEV;
	if (err < 0) {
		mutex_unlock(&snd_card_mutex);
		dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
			 idx, snd_ecards_limit - 1, err);
		kfree(card);
		return err;
	}
	set_bit(idx, snd_cards_lock);		/* lock it */
	if (idx >= snd_ecards_limit)
		snd_ecards_limit = idx + 1; /* increase the limit */
	mutex_unlock(&snd_card_mutex);
	card->dev = parent;
	card->number = idx;
	card->module = module;
	INIT_LIST_HEAD(&card->devices);
	init_rwsem(&card->controls_rwsem);
	rwlock_init(&card->ctl_files_rwlock);
	INIT_LIST_HEAD(&card->controls);
	INIT_LIST_HEAD(&card->ctl_files);
	spin_lock_init(&card->files_lock);
	INIT_LIST_HEAD(&card->files_list);
#ifdef CONFIG_PM
	init_waitqueue_head(&card->power_sleep);
#endif
	init_waitqueue_head(&card->remove_sleep);

	device_initialize(&card->card_dev);
	card->card_dev.parent = parent;
	card->card_dev.class = sound_class;
	card->card_dev.release = release_card_device;
	card->card_dev.groups = card->dev_groups;
	card->dev_groups[0] = &card_dev_attr_group;
	err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
	if (err < 0)
		goto __error;

	snprintf(card->irq_descr, sizeof(card->irq_descr), "%s:%s",
		 dev_driver_string(card->dev), dev_name(&card->card_dev));

	/* the control interface cannot be accessed from the user space until */
	/* snd_cards_bitmask and snd_cards are set with snd_card_register */
	err = snd_ctl_create(card);
	if (err < 0) {
		dev_err(parent, "unable to register control minors\n");
		goto __error;
	}
	err = snd_info_card_create(card);
	if (err < 0) {
		dev_err(parent, "unable to create card info\n");
		goto __error_ctl;
	}
	*card_ret = card;
	return 0;

      __error_ctl:
	snd_device_free_all(card);
      __error:
	put_device(&card->card_dev);
  	return err;
}


void snd_card_disconnect_sync(struct snd_card *card)
{
	int err;

	err = snd_card_disconnect(card);
	if (err < 0) {
		dev_err(card->dev,
			"snd_card_disconnect error (%d), skipping sync\n",
			err);
		return;
	}

	spin_lock_irq(&card->files_lock);
	wait_event_lock_irq(card->remove_sleep,
			    list_empty(&card->files_list),
			    card->files_lock);
	spin_unlock_irq(&card->files_lock);
}


int snd_card_file_remove(struct snd_card *card, struct file *file)
{
	struct snd_monitor_file *mfile, *found = NULL;

	spin_lock(&card->files_lock);
	list_for_each_entry(mfile, &card->files_list, list) {
		if (mfile->file == file) {
			list_del(&mfile->list);
			spin_lock(&shutdown_lock);
			list_del(&mfile->shutdown_list);
			spin_unlock(&shutdown_lock);
			if (mfile->disconnected_f_op)
				fops_put(mfile->disconnected_f_op);
			found = mfile;
			break;
		}
	}
	if (list_empty(&card->files_list))
		wake_up_all(&card->remove_sleep);
	spin_unlock(&card->files_lock);
	if (!found) {
		dev_err(card->dev, "card file remove problem (%p)\n", file);
		return -ENOENT;
	}
	kfree(found);
	put_device(&card->card_dev);
	return 0;
}


int snd_info_card_free(struct snd_card *card)
{
	if (!card)
		return 0;
	snd_info_free_entry(card->proc_root);
	card->proc_root = NULL;
	return 0;
}


static int alloc_info_private(struct snd_info_entry *entry,
			      struct snd_info_private_data **ret)
{
	struct snd_info_private_data *data;

	if (!entry || !entry->p)
		return -ENODEV;
	if (!try_module_get(entry->module))
		return -EFAULT;
	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data) {
		module_put(entry->module);
		return -ENOMEM;
	}
	data->entry = entry;
	*ret = data;
	return 0;
}


static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
{
	struct snd_info_private_data *data;
	struct snd_info_entry *entry;
	loff_t ret = -EINVAL, size;

	data = file->private_data;
	entry = data->entry;
	mutex_lock(&entry->access);
	if (entry->c.ops->llseek) {
		offset = entry->c.ops->llseek(entry,
					      data->file_private_data,
					      file, offset, orig);
		goto out;
	}

	size = entry->size;
	switch (orig) {
	case SEEK_SET:
		break;
	case SEEK_CUR:
		offset += file->f_pos;
		break;
	case SEEK_END:
		if (!size)
			goto out;
		offset += size;
		break;
	default:
		goto out;
	}
	if (offset < 0)
		goto out;
	if (size && offset > size)
		offset = size;
	file->f_pos = offset;
	ret = offset;
 out:
	mutex_unlock(&entry->access);
	return ret;
}


int snd_info_card_create(struct snd_card *card)
{
	char str[8];
	struct snd_info_entry *entry;

	if (snd_BUG_ON(!card))
		return -ENXIO;

	sprintf(str, "card%i", card->number);
	entry = create_subdir(card->module, str);
	if (!entry)
		return -ENOMEM;
	card->proc_root = entry;

	return snd_card_ro_proc_new(card, "id", card, snd_card_id_read);
}


static void process_frame(struct camera_data *cam)
{
	static int frame_count;

	unsigned char *inbuff = cam->workbuff->data;

	DBG("Processing frame #%d, current:%d\n",
	    cam->workbuff->num, cam->curbuff->num);

	if(cam->workbuff->length > cam->workbuff->max_length)
		cam->workbuff->max_length = cam->workbuff->length;

	if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) {
		frame_count++;
	} else {
		cam->workbuff->status = FRAME_ERROR;
		DBG("Start of frame not found\n");
		return;
	}

	/***
	 * Now the output buffer should have a JPEG image in it.
	 ***/
	if(!cam->first_image_seen) {
		/* Always skip the first image after streaming
		 * starts. It is almost certainly corrupt. */
		cam->first_image_seen = 1;
		cam->workbuff->status = FRAME_EMPTY;
		return;
	}
	if (cam->workbuff->length > 3) {
		if(cam->mmapped &&
		   cam->workbuff->length < cam->workbuff->max_length) {
			/* No junk in the buffers */
			memset(cam->workbuff->data+cam->workbuff->length,
			       0, cam->workbuff->max_length-
				  cam->workbuff->length);
		}
		cam->workbuff->max_length = cam->workbuff->length;
		cam->workbuff->status = FRAME_READY;

		if(!cam->mmapped && cam->num_frames > 2) {
			/* During normal reading, the most recent
			 * frame will be read.  If the current frame
			 * hasn't started reading yet, it will never
			 * be read, so mark it empty.  If the buffer is
			 * mmapped, or we have few buffers, we need to
			 * wait for the user to free the buffer.
			 *
			 * NOTE: This is not entirely foolproof with 3
			 * buffers, but it would take an EXTREMELY
			 * overloaded system to cause problems (possible
			 * image data corruption).  Basically, it would
			 * need to take more time to execute cpia2_read
			 * than it would for the camera to send
			 * cam->num_frames-2 frames before problems
			 * could occur.
			 */
			cam->curbuff->status = FRAME_EMPTY;
		}
		cam->curbuff = cam->workbuff;
		cam->workbuff = cam->workbuff->next;
		DBG("Changed buffers, work:%d, current:%d\n",
		    cam->workbuff->num, cam->curbuff->num);
		return;
	} else {
		DBG("Not enough data for an image.\n");
	}

	cam->workbuff->status = FRAME_ERROR;
	return;
}


static void cpia2_usb_disconnect(struct usb_interface *intf)
{
	struct camera_data *cam = usb_get_intfdata(intf);
	usb_set_intfdata(intf, NULL);

	DBG("Stopping stream\n");
	cpia2_usb_stream_stop(cam);

	mutex_lock(&cam->v4l2_lock);
	DBG("Unregistering camera\n");
	cpia2_unregister_camera(cam);
	v4l2_device_disconnect(&cam->v4l2_dev);
	mutex_unlock(&cam->v4l2_lock);

	if(cam->buffers) {
		DBG("Wakeup waiting processes\n");
		cam->curbuff->status = FRAME_READY;
		cam->curbuff->length = 0;
		wake_up_interruptible(&cam->wq_stream);
	}

	v4l2_device_put(&cam->v4l2_dev);

	LOG("CPiA2 camera disconnected.\n");
}


static int zr364xx_board_init(struct zr364xx_camera *cam)
{
	struct zr364xx_pipeinfo *pipe = cam->pipe;
	unsigned long i;

	DBG("board init: %p\n", cam);
	memset(pipe, 0, sizeof(*pipe));
	pipe->cam = cam;
	pipe->transfer_size = BUFFER_SIZE;

	pipe->transfer_buffer = kzalloc(pipe->transfer_size,
					GFP_KERNEL);
	if (!pipe->transfer_buffer) {
		DBG("out of memory!\n");
		return -ENOMEM;
	}

	cam->b_acquire = 0;
	cam->frame_count = 0;

	/*** start create system buffers ***/
	for (i = 0; i < FRAMES; i++) {
		/* always allocate maximum size for system buffers */
		cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);

		DBG("valloc %p, idx %lu, pdata %p\n",
			&cam->buffer.frame[i], i,
			cam->buffer.frame[i].lpvbits);
		if (!cam->buffer.frame[i].lpvbits) {
			printk(KERN_INFO KBUILD_MODNAME ": out of memory. Using less frames\n");
			break;
		}
	}

	if (i == 0) {
		printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
		kfree(cam->pipe->transfer_buffer);
		cam->pipe->transfer_buffer = NULL;
		return -ENOMEM;
	} else
		cam->buffer.dwFrames = i;

	/* make sure internal states are set */
	for (i = 0; i < FRAMES; i++) {
		cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
		cam->buffer.frame[i].cur_size = 0;
	}

	cam->cur_frame = 0;
	cam->last_frame = -1;
	/*** end create system buffers ***/

	/* start read pipe */
	zr364xx_start_readpipe(cam);
	DBG(": board initialized\n");
	return 0;
}


static int zr364xx_vidioc_qbuf(struct file *file,
				void *priv,
				struct v4l2_buffer *p)
{
	int rc;
	struct zr364xx_camera *cam = video_drvdata(file);
	_DBG("%s\n", __func__);
	if (cam->owner && cam->owner != priv)
		return -EBUSY;
	rc = videobuf_qbuf(&cam->vb_vidq, p);
	return rc;
}


static int zr364xx_prepare(struct zr364xx_camera *cam)
{
	int res;
	int i, j;

	for (i = 0; init[cam->method][i].size != -1; i++) {
		res = send_control_msg(cam->udev, 1, init[cam->method][i].value,
				     0, init[cam->method][i].bytes,
				     init[cam->method][i].size);
		if (res < 0) {
			dev_err(&cam->udev->dev,
				"error during open sequence: %d\n", i);
			return res;
		}
	}

	cam->skip = 2;
	cam->last_frame = -1;
	cam->cur_frame = 0;
	cam->frame_count = 0;
	for (j = 0; j < FRAMES; j++) {
		cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
		cam->buffer.frame[j].cur_size = 0;
	}
	v4l2_ctrl_handler_setup(&cam->ctrl_handler);
	return 0;
}


static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
				    struct v4l2_format *f)
{
	struct zr364xx_camera *cam = video_drvdata(file);
	struct videobuf_queue *q = &cam->vb_vidq;
	char pixelformat_name[5];
	int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
	int i;

	if (ret < 0)
		return ret;

	mutex_lock(&q->vb_lock);

	if (videobuf_queue_is_busy(&cam->vb_vidq)) {
		DBG("%s queue busy\n", __func__);
		ret = -EBUSY;
		goto out;
	}

	if (cam->owner) {
		DBG("%s can't change format after started\n", __func__);
		ret = -EBUSY;
		goto out;
	}

	cam->width = f->fmt.pix.width;
	cam->height = f->fmt.pix.height;
	DBG("%s: %dx%d mode selected\n", __func__,
		 cam->width, cam->height);
	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
	f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
	cam->vb_vidq.field = f->fmt.pix.field;

	if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120)
		mode = 1;
	else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480)
		mode = 2;
	else
		mode = 0;

	m0d1[0] = mode;
	m1[2].value = 0xf000 + mode;
	m2[1].value = 0xf000 + mode;

	/* special case for METHOD3, the modes are different */
	if (cam->method == METHOD3) {
		switch (mode) {
		case 1:
			m2[1].value = 0xf000 + 4;
			break;
		case 2:
			m2[1].value = 0xf000 + 0;
			break;
		default:
			m2[1].value = 0xf000 + 1;
			break;
		}
	}

	header2[437] = cam->height / 256;
	header2[438] = cam->height % 256;
	header2[439] = cam->width / 256;
	header2[440] = cam->width % 256;

	for (i = 0; init[cam->method][i].size != -1; i++) {
		ret =
		    send_control_msg(cam->udev, 1, init[cam->method][i].value,
				     0, init[cam->method][i].bytes,
				     init[cam->method][i].size);
		if (ret < 0) {
			dev_err(&cam->udev->dev,
			   "error during resolution change sequence: %d\n", i);
			goto out;
		}
	}

	/* Added some delay here, since opening/closing the camera quickly,
	 * like Ekiga does during its startup, can crash the webcam
	 */
	mdelay(100);
	cam->skip = 2;
	ret = 0;

out:
	mutex_unlock(&q->vb_lock);

	DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
	    decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
	    f->fmt.pix.field);
	return ret;
}


static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
{
	cam->b_acquire = 0;
	return 0;
}


static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
				      struct v4l2_format *f)
{
	struct zr364xx_camera *cam = video_drvdata(file);
	char pixelformat_name[5];

	if (!cam)
		return -ENODEV;

	if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
		DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__,
		    decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
		return -EINVAL;
	}

	if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) &&
	    !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) {
		f->fmt.pix.width = 320;
		f->fmt.pix.height = 240;
	}

	f->fmt.pix.field = V4L2_FIELD_NONE;
	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
	f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
	DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
	    decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
	    f->fmt.pix.field);
	return 0;
}


static int smsusb_probe(struct usb_interface *intf,
			const struct usb_device_id *id)
{
	struct usb_device *udev = interface_to_usbdev(intf);
	char devpath[32];
	int i, rc;

	pr_info("board id=%lu, interface number %d\n",
		 id->driver_info,
		 intf->cur_altsetting->desc.bInterfaceNumber);

	if (sms_get_board(id->driver_info)->intf_num !=
	    intf->cur_altsetting->desc.bInterfaceNumber) {
		pr_debug("interface %d won't be used. Expecting interface %d to popup\n",
			intf->cur_altsetting->desc.bInterfaceNumber,
			sms_get_board(id->driver_info)->intf_num);
		return -ENODEV;
	}

	if (intf->num_altsetting > 1) {
		rc = usb_set_interface(udev,
				       intf->cur_altsetting->desc.bInterfaceNumber,
				       0);
		if (rc < 0) {
			pr_err("usb_set_interface failed, rc %d\n", rc);
			return rc;
		}
	}

	pr_debug("smsusb_probe %d\n",
	       intf->cur_altsetting->desc.bInterfaceNumber);
	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
		pr_debug("endpoint %d %02x %02x %d\n", i,
		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
		if (intf->cur_altsetting->endpoint[i].desc.bEndpointAddress &
		    USB_DIR_IN)
			rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev,
				intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));
		else
			rc = usb_clear_halt(udev, usb_sndbulkpipe(udev,
				intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));
	}
	if ((udev->actconfig->desc.bNumInterfaces == 2) &&
	    (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
		pr_debug("rom interface 0 is not used\n");
		return -ENODEV;
	}

	if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) {
		/* Detected a Siano Stellar uninitialized */

		snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
			 udev->bus->busnum, udev->devpath);
		pr_info("stellar device in cold state was found at %s.\n",
			devpath);
		rc = smsusb1_load_firmware(
				udev, smscore_registry_getmode(devpath),
				id->driver_info);

		/* This device will reset and gain another USB ID */
		if (!rc)
			pr_info("stellar device now in warm state\n");
		else
			pr_err("Failed to put stellar in warm state. Error: %d\n",
			       rc);

		return rc;
	} else {
		rc = smsusb_init_device(intf, id->driver_info);
	}

	pr_info("Device initialized with return code %d\n", rc);
	sms_board_load_modules(id->driver_info);
	return rc;
}


static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
{
	struct smsusb_device_t *dev = usb_get_intfdata(intf);
	printk(KERN_INFO "%s  Entering status %d.\n", __func__, msg.event);
	dev->state = SMSUSB_SUSPENDED;
	/*smscore_set_power_mode(dev, SMS_POWER_MODE_SUSPENDED);*/
	smsusb_stop_streaming(dev);
	return 0;
}


int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
		u8 index, u8 data)
{
	int ret;

	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
	return ret;
}


static void sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
{
	u8 tmp8, tmp82, ramtype;
	int bw = 0;
	char *ramtypetext1 = NULL;
	static const char ram_datarate[4] = {'S', 'S', 'D', 'D'};
	static const char ram_dynamictype[4] = {'D', 'G', 'D', 'G'};
	static const int busSDR[4]  = {64, 64, 128, 128};
	static const int busDDR[4]  = {32, 32,  64,  64};
	static const int busDDRA[4] = {64+32, 64+32, (64+32)*2, (64+32)*2};

	sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
	sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
	sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
	sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
	ramtype &= 0x03;
	switch ((tmp8 >> 2) & 0x03) {
	case 0:
		ramtypetext1 = "1 ch/1 r";
		if (tmp82 & 0x10)
			bw = 32;
		else
			bw = busSDR[(tmp8 & 0x03)];

		break;
	case 1:
		ramtypetext1 = "1 ch/2 r";
		sisusb->vramsize <<= 1;
		bw = busSDR[(tmp8 & 0x03)];
		break;
	case 2:
		ramtypetext1 = "asymmetric";
		sisusb->vramsize += sisusb->vramsize/2;
		bw = busDDRA[(tmp8 & 0x03)];
		break;
	case 3:
		ramtypetext1 = "2 channel";
		sisusb->vramsize <<= 1;
		bw = busDDR[(tmp8 & 0x03)];
		break;
	}

	dev_info(&sisusb->sisusb_dev->dev,
			"%dMB %s %cDR S%cRAM, bus width %d\n",
			sisusb->vramsize >> 20, ramtypetext1,
			ram_datarate[ramtype], ram_dynamictype[ramtype], bw);
}


static void sisusb_disconnect(struct usb_interface *intf)
{
	struct sisusb_usb_data *sisusb;

	/* This should *not* happen */
	sisusb = usb_get_intfdata(intf);
	if (!sisusb)
		return;

#ifdef CONFIG_USB_SISUSBVGA_CON
	sisusb_console_exit(sisusb);
#endif

	usb_deregister_dev(intf, &usb_sisusb_class);

	mutex_lock(&sisusb->lock);

	/* Wait for all URBs to complete and kill them in case (MUST do) */
	if (!sisusb_wait_all_out_complete(sisusb))
		sisusb_kill_all_busy(sisusb);

	usb_set_intfdata(intf, NULL);

	sisusb->present = 0;
	sisusb->ready = 0;

	mutex_unlock(&sisusb->lock);

	/* decrement our usage count */
	kref_put(&sisusb->kref, sisusb_delete);
}


static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
		u32 addr, u32 *data)
{
	struct sisusb_packet packet;
	int ret = 0;

	packet.address = addr & ~3;

	switch (addr & 3) {
	case 0:
		packet.header  = (type << 6) | 0x000f;
		ret = sisusb_send_packet(sisusb, 6, &packet);
		*data = packet.data;
		break;
	case 1:
		packet.header  = (type << 6) | 0x000e;
		ret = sisusb_send_packet(sisusb, 6, &packet);
		*data = packet.data >> 8;
		packet.header  = (type << 6) | 0x0001;
		packet.address = (addr & ~3) + 4;
		ret |= sisusb_send_packet(sisusb, 6, &packet);
		*data |= (packet.data << 24);
		break;
	case 2:
		packet.header  = (type << 6) | 0x000c;
		ret = sisusb_send_packet(sisusb, 6, &packet);
		*data = packet.data >> 16;
		packet.header  = (type << 6) | 0x0003;
		packet.address = (addr & ~3) + 4;
		ret |= sisusb_send_packet(sisusb, 6, &packet);
		*data |= (packet.data << 16);
		break;
	case 3:
		packet.header  = (type << 6) | 0x0008;
		ret = sisusb_send_packet(sisusb, 6, &packet);
		*data = packet.data >> 24;
		packet.header  = (type << 6) | 0x0007;
		packet.address = (addr & ~3) + 4;
		ret |= sisusb_send_packet(sisusb, 6, &packet);
		*data |= (packet.data << 8);
	}

	return ret;
}


static loff_t sisusb_lseek(struct file *file, loff_t offset, int orig)
{
	struct sisusb_usb_data *sisusb;
	loff_t ret;

	sisusb = file->private_data;
	if (!sisusb)
		return -ENODEV;

	mutex_lock(&sisusb->lock);

	/* Sanity check */
	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
		mutex_unlock(&sisusb->lock);
		return -ENODEV;
	}

	ret = no_seek_end_llseek(file, offset, orig);

	mutex_unlock(&sisusb->lock);
	return ret;
}


    std::string help() const override {
        return "Used to update a user, for example to change its password";
    }


    DeferredComparison operator!=(const BSONElement& other) const {
        return DeferredComparison(DeferredComparison::Type::kNE, *this, other);
    }


User::UserId V2UserDocumentParser::extractUserIDFromUserDocument(const BSONObj& doc) const {
    auto userId = doc[AuthorizationManager::USERID_FIELD_NAME];
    if (userId.isBinData(BinDataType::newUUID)) {
        auto id = userId.uuid();
        User::UserId ret;
        std::copy(id.begin(), id.end(), std::back_inserter(ret));
        return ret;
    }

    return User::UserId();
}


    std::string help() const override {
        return "Drops a single role.  Before deleting the role completely it must remove it "
               "from any users or roles that reference it.  If any errors occur in the middle "
               "of that process it's possible to be left in a state where the role has been "
               "removed from some user/roles but otherwise still exists.";
    }


Status _checkV2RolesArray(const BSONElement& rolesElement) {
    if (rolesElement.eoo()) {
        return _badValue("User document needs 'roles' field to be provided");
    }
    if (rolesElement.type() != Array) {
        return _badValue("'roles' field must be an array");
    }
    for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) {
        if ((*iter).type() != Object) {
            return _badValue("Elements in 'roles' array must objects");
        }
        Status status = V2UserDocumentParser::checkValidRoleObject((*iter).Obj());
        if (!status.isOK())
            return status;
    }
    return Status::OK();
}


    std::string help() const override {
        return "Returns information about roles.";
    }


    double _numberDouble() const {
        return ConstDataView(value()).read<LittleEndian<double>>();
    }


CmdRevokeRolesFromUser() : BasicCommand("revokeRolesFromUser") {}


    virtual Status checkAuthForCommand(Client* client,
                                       const std::string& dbname,
                                       const BSONObj& cmdObj) const {
        return auth::checkAuthForRevokePrivilegesFromRoleCommand(client, dbname, cmdObj);
    }


    Status _checkForSystemUser(const std::vector<UserName>& names) {
        if (std::any_of(names.begin(), names.end(), [&](const UserName& userName) {
                return (userName == internalSecurity.user->getName());
            })) {
            return {ErrorCodes::BadValue,
                    "Cannot set __system as a pinned user, it is always pinned"};
        }
        return Status::OK();
    }


    const char* valuestrsafe() const {
        return type() == mongo::String ? valuestr() : "";
    }


void AuthorizationManagerImpl::_updateCacheGeneration_inlock(const CacheGuard&) {
    _fetchGeneration = OID::gen();
}


bool AuthorizationSessionImpl::isAuthorizedToCreateRole(
    const struct auth::CreateOrUpdateRoleArgs& args) {
    // A user is allowed to create a role under either of two conditions.

    // The user may create a role if the authorization system says they are allowed to.
    if (isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(args.roleName.getDB()),
                                         ActionType::createRole)) {
        return true;
    }

    // The user may create a role if the localhost exception is enabled, and they already own the
    // role. This implies they have obtained the role through an external authorization mechanism.
    if (_externalState->shouldAllowLocalhost()) {
        for (const auto& user : _authenticatedUsers) {
            if (user->hasRole(args.roleName)) {
                return true;
            }
        }
        log() << "Not authorized to create the first role in the system '" << args.roleName
              << "' using the localhost exception. The user needs to acquire the role through "
                 "external authentication first.";
    }

    return false;
}