static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
{
	struct net_device *dev;
	struct nlattr **attrs = info->attrs;
	struct macsec_secy *secy;
	struct macsec_tx_sc *tx_sc;
	struct macsec_tx_sa *tx_sa;
	unsigned char assoc_num;
	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
	int err;

	if (!attrs[MACSEC_ATTR_IFINDEX])
		return -EINVAL;

	if (parse_sa_config(attrs, tb_sa))
		return -EINVAL;

	if (!validate_add_txsa(tb_sa))
		return -EINVAL;

	rtnl_lock();
	dev = get_dev_from_nl(genl_info_net(info), attrs);
	if (IS_ERR(dev)) {
		rtnl_unlock();
		return PTR_ERR(dev);
	}

	secy = &macsec_priv(dev)->secy;
	tx_sc = &secy->tx_sc;

	assoc_num = nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]);

	if (nla_len(tb_sa[MACSEC_SA_ATTR_KEY]) != secy->key_len) {
		pr_notice("macsec: nl: add_txsa: bad key length: %d != %d\n",
			  nla_len(tb_sa[MACSEC_SA_ATTR_KEY]), secy->key_len);
		rtnl_unlock();
		return -EINVAL;
	}

	tx_sa = rtnl_dereference(tx_sc->sa[assoc_num]);
	if (tx_sa) {
		rtnl_unlock();
		return -EBUSY;
	}

	tx_sa = kmalloc(sizeof(*tx_sa), GFP_KERNEL);
	if (!tx_sa) {
		rtnl_unlock();
		return -ENOMEM;
	}

	err = init_tx_sa(tx_sa, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
			 secy->key_len, secy->icv_len);
	if (err < 0) {
		kfree(tx_sa);
		rtnl_unlock();
		return err;
	}

	nla_memcpy(tx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN);

	spin_lock_bh(&tx_sa->lock);
	tx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
	spin_unlock_bh(&tx_sa->lock);

	if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
		tx_sa->active = !!nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);

	if (assoc_num == tx_sc->encoding_sa && tx_sa->active)
		secy->operational = true;

	rcu_assign_pointer(tx_sc->sa[assoc_num], tx_sa);

	rtnl_unlock();

	return 0;
}


static void free_rx_sc_rcu(struct rcu_head *head)
{
	struct macsec_rx_sc *rx_sc = container_of(head, struct macsec_rx_sc, rcu_head);

	free_percpu(rx_sc->stats);
	kfree(rx_sc);
}


static bool validate_add_rxsa(struct nlattr **attrs)
{
	if (!attrs[MACSEC_SA_ATTR_AN] ||
	    !attrs[MACSEC_SA_ATTR_KEY] ||
	    !attrs[MACSEC_SA_ATTR_KEYID])
		return false;

	if (nla_get_u8(attrs[MACSEC_SA_ATTR_AN]) >= MACSEC_NUM_AN)
		return false;

	if (attrs[MACSEC_SA_ATTR_PN] && nla_get_u32(attrs[MACSEC_SA_ATTR_PN]) == 0)
		return false;

	if (attrs[MACSEC_SA_ATTR_ACTIVE]) {
		if (nla_get_u8(attrs[MACSEC_SA_ATTR_ACTIVE]) > 1)
			return false;
	}

	if (nla_len(attrs[MACSEC_SA_ATTR_KEYID]) != MACSEC_KEYID_LEN)
		return false;

	return true;
}


static struct macsec_tx_sa *macsec_txsa_get(struct macsec_tx_sa __rcu *ptr)
{
	struct macsec_tx_sa *sa = rcu_dereference_bh(ptr);

	if (!sa || !sa->active)
		return NULL;

	if (!atomic_inc_not_zero(&sa->refcnt))
		return NULL;

	return sa;
}


static unsigned int macsec_hdr_len(bool sci_present)
{
	return macsec_sectag_len(sci_present) + ETH_HLEN;
}


static struct macsec_tx_sa *get_txsa_from_nl(struct net *net,
					     struct nlattr **attrs,
					     struct nlattr **tb_sa,
					     struct net_device **devp,
					     struct macsec_secy **secyp,
					     struct macsec_tx_sc **scp,
					     u8 *assoc_num)
{
	struct net_device *dev;
	struct macsec_secy *secy;
	struct macsec_tx_sc *tx_sc;
	struct macsec_tx_sa *tx_sa;

	if (!tb_sa[MACSEC_SA_ATTR_AN])
		return ERR_PTR(-EINVAL);

	*assoc_num = nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]);

	dev = get_dev_from_nl(net, attrs);
	if (IS_ERR(dev))
		return ERR_CAST(dev);

	if (*assoc_num >= MACSEC_NUM_AN)
		return ERR_PTR(-EINVAL);

	secy = &macsec_priv(dev)->secy;
	tx_sc = &secy->tx_sc;

	tx_sa = rtnl_dereference(tx_sc->sa[*assoc_num]);
	if (!tx_sa)
		return ERR_PTR(-ENODEV);

	*devp = dev;
	*scp = tx_sc;
	*secyp = secy;
	return tx_sa;
}


static void macsec_dellink(struct net_device *dev, struct list_head *head)
{
	struct macsec_dev *macsec = macsec_priv(dev);
	struct net_device *real_dev = macsec->real_dev;
	struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);

	macsec_common_dellink(dev, head);

	if (list_empty(&rxd->secys)) {
		netdev_rx_handler_unregister(real_dev);
		kfree(rxd);
	}
}


static void macsec_fill_sectag(struct macsec_eth_header *h,
			       const struct macsec_secy *secy, u32 pn,
			       bool sci_present)
{
	const struct macsec_tx_sc *tx_sc = &secy->tx_sc;

	memset(&h->tci_an, 0, macsec_sectag_len(sci_present));
	h->eth.h_proto = htons(ETH_P_MACSEC);

	if (sci_present) {
		h->tci_an |= MACSEC_TCI_SC;
		memcpy(&h->secure_channel_id, &secy->sci,
		       sizeof(h->secure_channel_id));
	} else {
		if (tx_sc->end_station)
			h->tci_an |= MACSEC_TCI_ES;
		if (tx_sc->scb)
			h->tci_an |= MACSEC_TCI_SCB;
	}

	h->packet_number = htonl(pn);

	/* with GCM, C/E clear for !encrypt, both set for encrypt */
	if (tx_sc->encrypt)
		h->tci_an |= MACSEC_TCI_CONFID;
	else if (secy->icv_len != DEFAULT_ICV_LEN)
		h->tci_an |= MACSEC_TCI_C;

	h->tci_an |= tx_sc->encoding_sa;
}


static void macsec_dev_uninit(struct net_device *dev)
{
	struct macsec_dev *macsec = macsec_priv(dev);

	gro_cells_destroy(&macsec->gro_cells);
	free_percpu(dev->tstats);
}


static void macsec_fill_iv(unsigned char *iv, sci_t sci, u32 pn)
{
	struct gcm_iv *gcm_iv = (struct gcm_iv *)iv;

	gcm_iv->sci = sci;
	gcm_iv->pn = htonl(pn);
}


cr_input_consume_chars (CRInput * a_this, guint32 a_char, gulong * a_nb_char)
{
        enum CRStatus status = CR_OK;
        gulong nb_consumed = 0;

        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char,
                              CR_BAD_PARAM_ERROR);

        g_return_val_if_fail (a_char != 0 || a_nb_char != NULL,
                              CR_BAD_PARAM_ERROR);

        for (nb_consumed = 0; ((status == CR_OK)
                               && (*a_nb_char > 0
                                   && nb_consumed < *a_nb_char));
             nb_consumed++) {
                status = cr_input_consume_char (a_this, a_char);
        }

        *a_nb_char = nb_consumed;

        if ((nb_consumed > 0)
            && ((status == CR_PARSING_ERROR)
                || (status == CR_END_OF_INPUT_ERROR))) {
                status = CR_OK;
        }

        return status;
}


static void catc_ctrl_done(struct urb *urb)
{
	struct catc *catc = urb->context;
	struct ctrl_queue *q;
	unsigned long flags;
	int status = urb->status;

	if (status)
		dev_dbg(&urb->dev->dev, "ctrl_done, status %d, len %d.\n",
			status, urb->actual_length);

	spin_lock_irqsave(&catc->ctrl_lock, flags);

	q = catc->ctrl_queue + catc->ctrl_tail;

	if (q->dir) {
		if (q->buf && q->len)
			memcpy(q->buf, catc->ctrl_buf, q->len);
		else
			q->buf = catc->ctrl_buf;
	}

	if (q->callback)
		q->callback(catc, q);

	catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);

	if (catc->ctrl_head != catc->ctrl_tail)
		catc_ctrl_run(catc);
	else
		clear_bit(CTRL_RUNNING, &catc->flags);

	spin_unlock_irqrestore(&catc->ctrl_lock, flags);
}


static int catc_stop(struct net_device *netdev)
{
	struct catc *catc = netdev_priv(netdev);

	netif_stop_queue(netdev);

	if (!catc->is_f5u011)
		del_timer_sync(&catc->timer);

	usb_kill_urb(catc->rx_urb);
	usb_kill_urb(catc->tx_urb);
	usb_kill_urb(catc->irq_urb);
	usb_kill_urb(catc->ctrl_urb);

	return 0;
}


static int cp2112_hid_get(struct hid_device *hdev, unsigned char report_number,
			  u8 *data, size_t count, unsigned char report_type)
{
	u8 *buf;
	int ret;

	buf = kmalloc(count, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	ret = hid_hw_raw_request(hdev, report_number, buf, count,
				       report_type, HID_REQ_GET_REPORT);
	memcpy(data, buf, count);
	kfree(buf);
	return ret;
}


static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
{
	int i;
	u8 obuf[] = { 0x1f, 0xf0 };
	u8 ibuf[] = { 0 };
	struct i2c_msg msg[] = {
		{
			.addr = 0x51,
			.flags = 0,
			.buf = obuf,
			.len = 2,
		}, {
			.addr = 0x51,
			.flags = I2C_M_RD,
			.buf = ibuf,
			.len = 1,

		}
	};

	for (i = 0; i < 6; i++) {
		obuf[1] = 0xf0 + i;
		if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
			break;
		else
			mac[i] = ibuf[0];
	}

	return 0;
}


static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
{
	int i;
	u8 ibuf[] = {0, 0};
	u8 eeprom[256], eepromline[16];

	for (i = 0; i < 256; i++) {
		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
			err("read eeprom failed.");
			return -1;
		} else {
			eepromline[i%16] = ibuf[0];
			eeprom[i] = ibuf[0];
		}
		if ((i % 16) == 15) {
			deb_xfer("%02x: ", i - 15);
			debug_dump(eepromline, 16, deb_xfer);
		}
	}

	memcpy(mac, eeprom + 8, 6);
	return 0;
};


static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
{
	if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
		/*dw2102_properties.adapter->tuner_attach = NULL;*/
		d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
					&d->dev->i2c_adap);
		if (d->fe_adap[0].fe != NULL) {
			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
			info("Attached si21xx!");
			return 0;
		}
	}

	if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
		d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
					&d->dev->i2c_adap);
		if (d->fe_adap[0].fe != NULL) {
			if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
					&d->dev->i2c_adap)) {
				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
				info("Attached stv0288!");
				return 0;
			}
		}
	}

	if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
		d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
					&d->dev->i2c_adap);
		if (d->fe_adap[0].fe != NULL) {
			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
			info("Attached stv0299!");
			return 0;
		}
	}
	return -EIO;
}


static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
{
	static u8 led_off[] = { 0 };
	static u8 led_on[] = { 1 };
	struct i2c_msg msg = {
		.addr = DW2102_LED_CTRL,
		.flags = 0,
		.buf = led_off,
		.len = 1
	};
	struct dvb_usb_adapter *udev_adap =
		(struct dvb_usb_adapter *)(fe->dvb->priv);

	if (offon)
		msg.buf = led_on;
	i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
}


static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
{
	return I2C_FUNC_I2C;
}


int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
			       int *pos)
{
	u8 *b = (u8 *) &fw->data[*pos];
	int data_offs = 4;
	if (*pos >= fw->size)
		return 0;

	memset(hx,0,sizeof(struct hexline));

	hx->len  = b[0];

	if ((*pos + hx->len + 4) >= fw->size)
		return -EINVAL;

	hx->addr = b[1] | (b[2] << 8);
	hx->type = b[3];

	if (hx->type == 0x04) {
		/* b[4] and b[5] are the Extended linear address record data field */
		hx->addr |= (b[4] << 24) | (b[5] << 16);
/*		hx->len -= 2;
		data_offs += 2; */
	}
	memcpy(hx->data,&b[data_offs],hx->len);
	hx->chk = b[hx->len + data_offs];

	*pos += hx->len + 5;

	return *pos;
}


static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
{
	adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
			      &adap->dev->i2c_adap);
	if (adap->fe_adap[0].fe != NULL)
		return 0;

	return -EIO;
}


static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
{
	int rc = 0;

	rc = cxusb_power_ctrl(d, onoff);
	if (!onoff)
		cxusb_nano2_led(d, 0);

	return rc;
}


static int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
{
	dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
			adap->id);

	if (adap->dvb_adap.priv) {
		dvb_net_release(&adap->dvb_net);
		adap->demux.dmx.close(&adap->demux.dmx);
		dvb_dmxdev_release(&adap->dmxdev);
		dvb_dmx_release(&adap->demux);
		dvb_unregister_adapter(&adap->dvb_adap);
	}

	return 0;
}


static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d)
{
	dev_dbg(&d->udev->dev, "%s:\n", __func__);

	if (d->i2c_adap.algo)
		i2c_del_adapter(&d->i2c_adap);

	return 0;
}


static int crypto_ccm_decrypt(struct aead_request *req)
{
	struct crypto_aead *aead = crypto_aead_reqtfm(req);
	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
	struct skcipher_request *skreq = &pctx->skreq;
	struct scatterlist *dst;
	unsigned int authsize = crypto_aead_authsize(aead);
	unsigned int cryptlen = req->cryptlen;
	u8 *authtag = pctx->auth_tag;
	u8 *odata = pctx->odata;
	u8 *iv = req->iv;
	int err;

	cryptlen -= authsize;

	err = crypto_ccm_init_crypt(req, authtag);
	if (err)
		return err;

	scatterwalk_map_and_copy(authtag, sg_next(pctx->src), cryptlen,
				 authsize, 0);

	dst = pctx->src;
	if (req->src != req->dst)
		dst = pctx->dst;

	skcipher_request_set_tfm(skreq, ctx->ctr);
	skcipher_request_set_callback(skreq, pctx->flags,
				      crypto_ccm_decrypt_done, req);
	skcipher_request_set_crypt(skreq, pctx->src, dst, cryptlen + 16, iv);
	err = crypto_skcipher_decrypt(skreq);
	if (err)
		return err;

	err = crypto_ccm_auth(req, sg_next(dst), cryptlen);
	if (err)
		return err;

	/* verify */
	if (crypto_memneq(authtag, odata, authsize))
		return -EBADMSG;

	return err;
}


static int crypto_ccm_create(struct crypto_template *tmpl, struct rtattr **tb)
{
	const char *cipher_name;
	char ctr_name[CRYPTO_MAX_ALG_NAME];
	char mac_name[CRYPTO_MAX_ALG_NAME];
	char full_name[CRYPTO_MAX_ALG_NAME];

	cipher_name = crypto_attr_alg_name(tb[1]);
	if (IS_ERR(cipher_name))
		return PTR_ERR(cipher_name);

	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)",
		     cipher_name) >= CRYPTO_MAX_ALG_NAME)
		return -ENAMETOOLONG;

	if (snprintf(mac_name, CRYPTO_MAX_ALG_NAME, "cbcmac(%s)",
		     cipher_name) >= CRYPTO_MAX_ALG_NAME)
		return -ENAMETOOLONG;

	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm(%s)", cipher_name) >=
	    CRYPTO_MAX_ALG_NAME)
		return -ENAMETOOLONG;

	return crypto_ccm_create_common(tmpl, tb, full_name, ctr_name,
					mac_name);
}


static void crypto_rfc4309_exit_tfm(struct crypto_aead *tfm)
{
	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(tfm);

	crypto_free_aead(ctx->child);
}


static struct gs_can *gs_make_candev(unsigned int channel,
				     struct usb_interface *intf,
				     struct gs_device_config *dconf)
{
	struct gs_can *dev;
	struct net_device *netdev;
	int rc;
	struct gs_device_bt_const *bt_const;

	bt_const = kmalloc(sizeof(*bt_const), GFP_KERNEL);
	if (!bt_const)
		return ERR_PTR(-ENOMEM);

	/* fetch bit timing constants */
	rc = usb_control_msg(interface_to_usbdev(intf),
			     usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
			     GS_USB_BREQ_BT_CONST,
			     USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
			     channel,
			     0,
			     bt_const,
			     sizeof(*bt_const),
			     1000);

	if (rc < 0) {
		dev_err(&intf->dev,
			"Couldn't get bit timing const for channel (err=%d)\n",
			rc);
		kfree(bt_const);
		return ERR_PTR(rc);
	}

	/* create netdev */
	netdev = alloc_candev(sizeof(struct gs_can), GS_MAX_TX_URBS);
	if (!netdev) {
		dev_err(&intf->dev, "Couldn't allocate candev\n");
		kfree(bt_const);
		return ERR_PTR(-ENOMEM);
	}

	dev = netdev_priv(netdev);

	netdev->netdev_ops = &gs_usb_netdev_ops;

	netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */

	/* dev settup */
	strcpy(dev->bt_const.name, "gs_usb");
	dev->bt_const.tseg1_min = bt_const->tseg1_min;
	dev->bt_const.tseg1_max = bt_const->tseg1_max;
	dev->bt_const.tseg2_min = bt_const->tseg2_min;
	dev->bt_const.tseg2_max = bt_const->tseg2_max;
	dev->bt_const.sjw_max = bt_const->sjw_max;
	dev->bt_const.brp_min = bt_const->brp_min;
	dev->bt_const.brp_max = bt_const->brp_max;
	dev->bt_const.brp_inc = bt_const->brp_inc;

	dev->udev = interface_to_usbdev(intf);
	dev->iface = intf;
	dev->netdev = netdev;
	dev->channel = channel;

	init_usb_anchor(&dev->tx_submitted);
	atomic_set(&dev->active_tx_urbs, 0);
	spin_lock_init(&dev->tx_ctx_lock);
	for (rc = 0; rc < GS_MAX_TX_URBS; rc++) {
		dev->tx_context[rc].dev = dev;
		dev->tx_context[rc].echo_id = GS_MAX_TX_URBS;
	}

	/* can settup */
	dev->can.state = CAN_STATE_STOPPED;
	dev->can.clock.freq = bt_const->fclk_can;
	dev->can.bittiming_const = &dev->bt_const;
	dev->can.do_set_bittiming = gs_usb_set_bittiming;

	dev->can.ctrlmode_supported = 0;

	if (bt_const->feature & GS_CAN_FEATURE_LISTEN_ONLY)
		dev->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;

	if (bt_const->feature & GS_CAN_FEATURE_LOOP_BACK)
		dev->can.ctrlmode_supported |= CAN_CTRLMODE_LOOPBACK;

	if (bt_const->feature & GS_CAN_FEATURE_TRIPLE_SAMPLE)
		dev->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;

	if (bt_const->feature & GS_CAN_FEATURE_ONE_SHOT)
		dev->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;

	SET_NETDEV_DEV(netdev, &intf->dev);

	if (dconf->sw_version > 1)
		if (bt_const->feature & GS_CAN_FEATURE_IDENTIFY)
			netdev->ethtool_ops = &gs_usb_ethtool_ops;

	kfree(bt_const);

	rc = register_candev(dev->netdev);
	if (rc) {
		free_candev(dev->netdev);
		dev_err(&intf->dev, "Couldn't register candev (err=%d)\n", rc);
		return ERR_PTR(rc);
	}

	return dev;
}


static void gs_free_tx_context(struct gs_tx_context *txc)
{
	txc->echo_id = GS_MAX_TX_URBS;
}


static void free_buf(struct port_buffer *buf, bool can_sleep)
{
	unsigned int i;

	for (i = 0; i < buf->sgpages; i++) {
		struct page *page = sg_page(&buf->sg[i]);
		if (!page)
			break;
		put_page(page);
	}

	if (!buf->dev) {
		kfree(buf->buf);
	} else if (is_rproc_enabled) {
		unsigned long flags;

		/* dma_free_coherent requires interrupts to be enabled. */
		if (!can_sleep) {
			/* queue up dma-buffers to be freed later */
			spin_lock_irqsave(&dma_bufs_lock, flags);
			list_add_tail(&buf->list, &pending_free_dma_bufs);
			spin_unlock_irqrestore(&dma_bufs_lock, flags);
			return;
		}
		dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma);

		/* Release device refcnt and allow it to be freed */
		put_device(buf->dev);
	}

	kfree(buf);
}


static void in_intr(struct virtqueue *vq)
{
	struct port *port;
	unsigned long flags;

	port = find_port_by_vq(vq->vdev->priv, vq);
	if (!port)
		return;

	spin_lock_irqsave(&port->inbuf_lock, flags);
	port->inbuf = get_inbuf(port);

	/*
	 * Normally the port should not accept data when the port is
	 * closed. For generic serial ports, the host won't (shouldn't)
	 * send data till the guest is connected. But this condition
	 * can be reached when a console port is not yet connected (no
	 * tty is spawned) and the other side sends out data over the
	 * vring, or when a remote devices start sending data before
	 * the ports are opened.
	 *
	 * A generic serial port will discard data if not connected,
	 * while console ports and rproc-serial ports accepts data at
	 * any time. rproc-serial is initiated with guest_connected to
	 * false because port_fops_open expects this. Console ports are
	 * hooked up with an HVC console and is initialized with
	 * guest_connected to true.
	 */

	if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev))
		discard_port_data(port);

	/* Send a SIGIO indicating new data in case the process asked for it */
	send_sigio_to_port(port);

	spin_unlock_irqrestore(&port->inbuf_lock, flags);

	wake_up_interruptible(&port->waitqueue);

	if (is_console_port(port) && hvc_poll(port->cons.hvc))
		hvc_kick();
}


static int init_vqs(struct ports_device *portdev)
{
	vq_callback_t **io_callbacks;
	char **io_names;
	struct virtqueue **vqs;
	u32 i, j, nr_ports, nr_queues;
	int err;

	nr_ports = portdev->max_nr_ports;
	nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;

	vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
	io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
	io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
	portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
				  GFP_KERNEL);
	portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
				   GFP_KERNEL);
	if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
	    !portdev->out_vqs) {
		err = -ENOMEM;
		goto free;
	}

	/*
	 * For backward compat (newer host but older guest), the host
	 * spawns a console port first and also inits the vqs for port
	 * 0 before others.
	 */
	j = 0;
	io_callbacks[j] = in_intr;
	io_callbacks[j + 1] = out_intr;
	io_names[j] = "input";
	io_names[j + 1] = "output";
	j += 2;

	if (use_multiport(portdev)) {
		io_callbacks[j] = control_intr;
		io_callbacks[j + 1] = NULL;
		io_names[j] = "control-i";
		io_names[j + 1] = "control-o";

		for (i = 1; i < nr_ports; i++) {
			j += 2;
			io_callbacks[j] = in_intr;
			io_callbacks[j + 1] = out_intr;
			io_names[j] = "input";
			io_names[j + 1] = "output";
		}
	}
	/* Find the queues. */
	err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
					      io_callbacks,
					      (const char **)io_names, NULL);
	if (err)
		goto free;

	j = 0;
	portdev->in_vqs[0] = vqs[0];
	portdev->out_vqs[0] = vqs[1];
	j += 2;
	if (use_multiport(portdev)) {
		portdev->c_ivq = vqs[j];
		portdev->c_ovq = vqs[j + 1];

		for (i = 1; i < nr_ports; i++) {
			j += 2;
			portdev->in_vqs[i] = vqs[j];
			portdev->out_vqs[i] = vqs[j + 1];
		}
	}
	kfree(io_names);
	kfree(io_callbacks);
	kfree(vqs);

	return 0;

free:
	kfree(portdev->out_vqs);
	kfree(portdev->in_vqs);
	kfree(io_names);
	kfree(io_callbacks);
	kfree(vqs);

	return err;
}


static void handle_control_message(struct virtio_device *vdev,
				   struct ports_device *portdev,
				   struct port_buffer *buf)
{
	struct virtio_console_control *cpkt;
	struct port *port;
	size_t name_size;
	int err;

	cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);

	port = find_port_by_id(portdev, virtio32_to_cpu(vdev, cpkt->id));
	if (!port &&
	    cpkt->event != cpu_to_virtio16(vdev, VIRTIO_CONSOLE_PORT_ADD)) {
		/* No valid header at start of buffer.  Drop it. */
		dev_dbg(&portdev->vdev->dev,
			"Invalid index %u in control packet\n", cpkt->id);
		return;
	}

	switch (virtio16_to_cpu(vdev, cpkt->event)) {
	case VIRTIO_CONSOLE_PORT_ADD:
		if (port) {
			dev_dbg(&portdev->vdev->dev,
				"Port %u already added\n", port->id);
			send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
			break;
		}
		if (virtio32_to_cpu(vdev, cpkt->id) >=
		    portdev->max_nr_ports) {
			dev_warn(&portdev->vdev->dev,
				"Request for adding port with "
				"out-of-bound id %u, max. supported id: %u\n",
				cpkt->id, portdev->max_nr_ports - 1);
			break;
		}
		add_port(portdev, virtio32_to_cpu(vdev, cpkt->id));
		break;
	case VIRTIO_CONSOLE_PORT_REMOVE:
		unplug_port(port);
		break;
	case VIRTIO_CONSOLE_CONSOLE_PORT:
		if (!cpkt->value)
			break;
		if (is_console_port(port))
			break;

		init_port_console(port);
		complete(&early_console_added);
		/*
		 * Could remove the port here in case init fails - but
		 * have to notify the host first.
		 */
		break;
	case VIRTIO_CONSOLE_RESIZE: {
		struct {
			__u16 rows;
			__u16 cols;
		} size;

		if (!is_console_port(port))
			break;

		memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt),
		       sizeof(size));
		set_console_size(port, size.rows, size.cols);

		port->cons.hvc->irq_requested = 1;
		resize_console(port);
		break;
	}
	case VIRTIO_CONSOLE_PORT_OPEN:
		port->host_connected = virtio16_to_cpu(vdev, cpkt->value);
		wake_up_interruptible(&port->waitqueue);
		/*
		 * If the host port got closed and the host had any
		 * unconsumed buffers, we'll be able to reclaim them
		 * now.
		 */
		spin_lock_irq(&port->outvq_lock);
		reclaim_consumed_buffers(port);
		spin_unlock_irq(&port->outvq_lock);

		/*
		 * If the guest is connected, it'll be interested in
		 * knowing the host connection state changed.
		 */
		spin_lock_irq(&port->inbuf_lock);
		send_sigio_to_port(port);
		spin_unlock_irq(&port->inbuf_lock);
		break;
	case VIRTIO_CONSOLE_PORT_NAME:
		/*
		 * If we woke up after hibernation, we can get this
		 * again.  Skip it in that case.
		 */
		if (port->name)
			break;

		/*
		 * Skip the size of the header and the cpkt to get the size
		 * of the name that was sent
		 */
		name_size = buf->len - buf->offset - sizeof(*cpkt) + 1;

		port->name = kmalloc(name_size, GFP_KERNEL);
		if (!port->name) {
			dev_err(port->dev,
				"Not enough space to store port name\n");
			break;
		}
		strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
			name_size - 1);
		port->name[name_size - 1] = 0;

		/*
		 * Since we only have one sysfs attribute, 'name',
		 * create it only if we have a name for the port.
		 */
		err = sysfs_create_group(&port->dev->kobj,
					 &port_attribute_group);
		if (err) {
			dev_err(port->dev,
				"Error %d creating sysfs device attributes\n",
				err);
		} else {
			/*
			 * Generate a udev event so that appropriate
			 * symlinks can be created based on udev
			 * rules.
			 */
			kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
		}
		break;
	}
}


static void reclaim_consumed_buffers(struct port *port)
{
	struct port_buffer *buf;
	unsigned int len;

	if (!port->portdev) {
		/* Device has been unplugged.  vqs are already gone. */
		return;
	}
	while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
		free_buf(buf, false);
		port->outvq_full = false;
	}
}


static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd)
{
	return __mii_op(pegasus, phy, indx, regd, PHY_WRITE);
}


static inline void enable_eprom_write(pegasus_t *pegasus)
{
	__u8 tmp;

	get_registers(pegasus, EthCtrl2, 1, &tmp);
	set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
}


static __u8 mii_phy_probe(pegasus_t *pegasus)
{
	int i;
	__u16 tmp;

	for (i = 0; i < 32; i++) {
		read_mii_word(pegasus, i, MII_BMSR, &tmp);
		if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0)
			continue;
		else
			return i;
	}

	return 0xff;
}


static int alloc_urbs(pegasus_t *pegasus)
{
	int res = -ENOMEM;

	pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!pegasus->rx_urb) {
		return res;
	}
	pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!pegasus->tx_urb) {
		usb_free_urb(pegasus->rx_urb);
		return res;
	}
	pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!pegasus->intr_urb) {
		usb_free_urb(pegasus->tx_urb);
		usb_free_urb(pegasus->rx_urb);
		return res;
	}

	return 0;
}


pegasus_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
	pegasus_t	*pegasus = netdev_priv(dev);

	wol->supported = WAKE_MAGIC | WAKE_PHY;
	wol->wolopts = pegasus->wolopts;
}


static int __mii_op(pegasus_t *p, __u8 phy, __u8 indx, __u16 *regd, __u8 cmd)
{
	int i;
	__u8 data[4] = { phy, 0, 0, indx };
	__le16 regdi;
	int ret = -ETIMEDOUT;

	if (cmd & PHY_WRITE) {
		__le16 *t = (__le16 *) & data[1];
		*t = cpu_to_le16(*regd);
	}
	set_register(p, PhyCtrl, 0);
	set_registers(p, PhyAddr, sizeof(data), data);
	set_register(p, PhyCtrl, (indx | cmd));
	for (i = 0; i < REG_TIMEOUT; i++) {
		ret = get_registers(p, PhyCtrl, 1, data);
		if (ret < 0)
			goto fail;
		if (data[0] & PHY_DONE)
			break;
	}
	if (i >= REG_TIMEOUT)
		goto fail;
	if (cmd & PHY_READ) {
		ret = get_registers(p, PhyData, 2, &regdi);
		*regd = le16_to_cpu(regdi);
		return ret;
	}
	return 0;
fail:
	netif_dbg(p, drv, p->net, "%s failed\n", __func__);
	return ret;
}


static void async_ctrl_callback(struct urb *urb)
{
	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
	int status = urb->status;

	if (status < 0)
		dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status);
	kfree(req);
	usb_free_urb(urb);
}


static inline void disable_eprom_write(pegasus_t *pegasus)
{
	__u8 tmp;

	get_registers(pegasus, EthCtrl2, 1, &tmp);
	set_register(pegasus, EpromCtrl, 0);
	set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
}


static void unlink_all_urbs(pegasus_t *pegasus)
{
	usb_kill_urb(pegasus->intr_urb);
	usb_kill_urb(pegasus->tx_urb);
	usb_kill_urb(pegasus->rx_urb);
}


static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
	__u16 *data = (__u16 *) &rq->ifr_ifru;
	pegasus_t *pegasus = netdev_priv(net);
	int res;

	switch (cmd) {
	case SIOCDEVPRIVATE:
		data[0] = pegasus->phy;
	case SIOCDEVPRIVATE + 1:
		read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]);
		res = 0;
		break;
	case SIOCDEVPRIVATE + 2:
		if (!capable(CAP_NET_ADMIN))
			return -EPERM;
		write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, &data[2]);
		res = 0;
		break;
	default:
		res = -EOPNOTSUPP;
	}
	return res;
}


static void pegasus_set_multicast(struct net_device *net)
{
	pegasus_t *pegasus = netdev_priv(net);

	if (net->flags & IFF_PROMISC) {
		pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
		netif_info(pegasus, link, net, "Promiscuous mode enabled\n");
	} else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) {
		pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
		netif_dbg(pegasus, link, net, "set allmulti\n");
	} else {
		pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
	}
	update_eth_regs_async(pegasus);
}


static void rx_fixup(unsigned long data)
{
	struct rtl8150 *dev = (struct rtl8150 *)data;
	struct sk_buff *skb;
	int status;

	spin_lock_irq(&dev->rx_pool_lock);
	fill_skb_pool(dev);
	spin_unlock_irq(&dev->rx_pool_lock);
	if (test_bit(RX_URB_FAIL, &dev->flags))
		if (dev->rx_skb)
			goto try_again;
	spin_lock_irq(&dev->rx_pool_lock);
	skb = pull_skb(dev);
	spin_unlock_irq(&dev->rx_pool_lock);
	if (skb == NULL)
		goto tlsched;
	dev->rx_skb = skb;
	usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
		      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
try_again:
	status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
	if (status == -ENODEV) {
		netif_device_detach(dev->netdev);
	} else if (status) {
		set_bit(RX_URB_FAIL, &dev->flags);
		goto tlsched;
	} else {
		clear_bit(RX_URB_FAIL, &dev->flags);
	}

	return;
tlsched:
	tasklet_schedule(&dev->tl);
}


static int rtl8150_reset(rtl8150_t * dev)
{
	u8 data = 0x10;
	int i = HZ;

	set_registers(dev, CR, 1, &data);
	do {
		get_registers(dev, CR, 1, &data);
	} while ((data & 0x10) && --i);

	return (i > 0) ? 1 : 0;
}


static int rtl8150_resume(struct usb_interface *intf)
{
	rtl8150_t *dev = usb_get_intfdata(intf);

	netif_device_attach(dev->netdev);
	if (netif_running(dev->netdev)) {
		dev->rx_urb->status = 0;
		dev->rx_urb->actual_length = 0;
		read_bulk_callback(dev->rx_urb);

		dev->intr_urb->status = 0;
		dev->intr_urb->actual_length = 0;
		intr_callback(dev->intr_urb);
	}
	return 0;
}


static void read_bulk_callback(struct urb *urb)
{
	rtl8150_t *dev;
	unsigned pkt_len, res;
	struct sk_buff *skb;
	struct net_device *netdev;
	u16 rx_stat;
	int status = urb->status;
	int result;

	dev = urb->context;
	if (!dev)
		return;
	if (test_bit(RTL8150_UNPLUG, &dev->flags))
		return;
	netdev = dev->netdev;
	if (!netif_device_present(netdev))
		return;

	switch (status) {
	case 0:
		break;
	case -ENOENT:
		return;	/* the urb is in unlink state */
	case -ETIME:
		if (printk_ratelimit())
			dev_warn(&urb->dev->dev, "may be reset is needed?..\n");
		goto goon;
	default:
		if (printk_ratelimit())
			dev_warn(&urb->dev->dev, "Rx status %d\n", status);
		goto goon;
	}

	if (!dev->rx_skb)
		goto resched;
	/* protect against short packets (tell me why we got some?!?) */
	if (urb->actual_length < 4)
		goto goon;

	res = urb->actual_length;
	rx_stat = le16_to_cpu(*(__le16 *)(urb->transfer_buffer + res - 4));
	pkt_len = res - 4;

	skb_put(dev->rx_skb, pkt_len);
	dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);
	netif_rx(dev->rx_skb);
	netdev->stats.rx_packets++;
	netdev->stats.rx_bytes += pkt_len;

	spin_lock(&dev->rx_pool_lock);
	skb = pull_skb(dev);
	spin_unlock(&dev->rx_pool_lock);
	if (!skb)
		goto resched;

	dev->rx_skb = skb;
goon:
	usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
		      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
	result = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
	if (result == -ENODEV)
		netif_device_detach(dev->netdev);
	else if (result) {
		set_bit(RX_URB_FAIL, &dev->flags);
		goto resched;
	} else {
		clear_bit(RX_URB_FAIL, &dev->flags);
	}

	return;
resched:
	tasklet_schedule(&dev->tl);
}


static inline void set_ethernet_addr(rtl8150_t * dev)
{
	u8 node_id[6];

	get_registers(dev, IDR, sizeof(node_id), node_id);
	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
}


static int uint64_mul_overflow(uint64_t a, uint64_t b, uint64_t *res)
{
    *res = a * b;
    return (a > UINT64_MAX / b);
}


make_rss(i_ctx_t *i_ctx_p, os_ptr op, const byte * data, uint size,
         uint string_space, long offset, long length, bool is_bytestring)
{
    uint save_space = icurrent_space;
    stream *s;
    long left = min(length, size - offset);

    ialloc_set_space(idmemory, string_space);
    s = file_alloc_stream(imemory, "make_rss");
    ialloc_set_space(idmemory, save_space);
    if (s == 0)
        return_error(gs_error_VMerror);
    sread_string_reusable(s, data + offset, max(left, 0));
    if (is_bytestring)
        s->cbuf_string.data = 0;	/* byte array, not string */
    make_stream_file(op, s, "r");
    return 0;
}


zeqproc(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    ref2_t stack[MAX_DEPTH + 1];
    ref2_t *top = stack;

    check_op(2);
    if (!eqproc_check_type(op -1) || !eqproc_check_type(op)) {
        make_false(op - 1);
        pop(1);
        return 0;
    }

    make_array(&stack[0].proc1, 0, 1, op - 1);
    make_array(&stack[0].proc2, 0, 1, op);
    for (;;) {
        long i;

        if (r_size(&top->proc1) == 0) {
            /* Finished these arrays, go up to next level. */
            if (top == stack) {
                /* We're done matching: it succeeded. */
                make_true(op - 1);
                pop(1);
                return 0;
            }
            --top;
            continue;
        }
        /* Look at the next elements of the arrays. */
        i = r_size(&top->proc1) - 1;
        array_get(imemory, &top->proc1, i, &top[1].proc1);
        array_get(imemory, &top->proc2, i, &top[1].proc2);
        r_dec_size(&top->proc1, 1);
        ++top;
        /*
         * Amazingly enough, the objects' executable attributes are not
         * required to match.  This means { x load } will match { /x load },
         * even though this is clearly wrong.
         */
#if 0
        if (r_has_attr(&top->proc1, a_executable) !=
            r_has_attr(&top->proc2, a_executable)
            )
            break;
#endif
        if (obj_eq(imemory, &top->proc1, &top->proc2)) {
            /* Names don't match strings. */
            if (r_type(&top->proc1) != r_type(&top->proc2) &&
                (r_type(&top->proc1) == t_name ||
                 r_type(&top->proc2) == t_name)
                )
                break;
            --top;		/* no recursion */
            continue;
        }
        if (r_is_array(&top->proc1) && r_is_array(&top->proc2) &&
            r_size(&top->proc1) == r_size(&top->proc2) &&
            top < stack + (MAX_DEPTH - 1)
            ) {
            /* Descend into the arrays. */
            continue;
        }
        break;
    }
    /* An exit from the loop indicates that matching failed. */
    make_false(op - 1);
    pop(1);
    return 0;
}


nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
					struct nfsd_attrstat *resp)
{
	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
	return xdr_ressize_check(rqstp, p);
}


nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
					struct nfsd3_readdirargs *args)
{
	p = decode_fh(p, &args->fh);
	if (!p)
		return 0;
	p = xdr_decode_hyper(p, &args->cookie);
	args->verf   = p; p += 2;
	args->dircount = ~0;
	args->count  = ntohl(*p++);
	args->count  = min_t(u32, args->count, PAGE_SIZE);
	args->buffer = page_address(*(rqstp->rq_next_page++));

	return xdr_argsize_check(rqstp, p);
}


static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp)
{
	u64 f;
	switch(fsid_source(fhp)) {
	default:
	case FSIDSOURCE_DEV:
		p = xdr_encode_hyper(p, (u64)huge_encode_dev
				     (fhp->fh_dentry->d_sb->s_dev));
		break;
	case FSIDSOURCE_FSID:
		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
		break;
	case FSIDSOURCE_UUID:
		f = ((u64*)fhp->fh_export->ex_uuid)[0];
		f ^= ((u64*)fhp->fh_export->ex_uuid)[1];
		p = xdr_encode_hyper(p, f);
		break;
	}
	return p;
}


nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
	return xdr_argsize_check(rqstp, p);
}


nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p,
					struct nfsd3_renameres *resp)
{
	p = encode_wcc_data(rqstp, p, &resp->ffh);
	p = encode_wcc_data(rqstp, p, &resp->tfh);
	return xdr_ressize_check(rqstp, p);
}


nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p,
					struct nfsd3_pathconfres *resp)
{
	*p++ = xdr_zero;	/* no post_op_attr */

	if (resp->status == 0) {
		*p++ = htonl(resp->p_link_max);
		*p++ = htonl(resp->p_name_max);
		*p++ = htonl(resp->p_no_trunc);
		*p++ = htonl(resp->p_chown_restricted);
		*p++ = htonl(resp->p_case_insensitive);
		*p++ = htonl(resp->p_case_preserving);
	}

	return xdr_ressize_check(rqstp, p);
}


nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p,
					struct nfsd3_attrstat *resp)
{
	p = encode_wcc_data(rqstp, p, &resp->fh);
	return xdr_ressize_check(rqstp, p);
}


nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
					struct nfsd_readdirres *resp)
{
	xdr_ressize_check(rqstp, p);
	p = resp->buffer;
	*p++ = 0;			/* no more entries */
	*p++ = htonl((resp->common.err == nfserr_eof));
	rqstp->rq_res.page_len = (((unsigned long)p-1) & ~PAGE_MASK)+1;

	return 1;
}


encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
	     loff_t offset, u64 ino, unsigned int d_type, int plus)
{
	struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
		       					common);
	__be32		*p = cd->buffer;
	caddr_t		curr_page_addr = NULL;
	struct page **	page;
	int		slen;		/* string (name) length */
	int		elen;		/* estimated entry length in words */
	int		num_entry_words = 0;	/* actual number of words */

	if (cd->offset) {
		u64 offset64 = offset;

		if (unlikely(cd->offset1)) {
			/* we ended up with offset on a page boundary */
			*cd->offset = htonl(offset64 >> 32);
			*cd->offset1 = htonl(offset64 & 0xffffffff);
			cd->offset1 = NULL;
		} else {
			xdr_encode_hyper(cd->offset, offset64);
		}
	}

	/*
	dprintk("encode_entry(%.*s @%ld%s)\n",
		namlen, name, (long) offset, plus? " plus" : "");
	 */

	/* truncate filename if too long */
	namlen = min(namlen, NFS3_MAXNAMLEN);

	slen = XDR_QUADLEN(namlen);
	elen = slen + NFS3_ENTRY_BAGGAGE
		+ (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);

	if (cd->buflen < elen) {
		cd->common.err = nfserr_toosmall;
		return -EINVAL;
	}

	/* determine which page in rq_respages[] we are currently filling */
	for (page = cd->rqstp->rq_respages + 1;
				page < cd->rqstp->rq_next_page; page++) {
		curr_page_addr = page_address(*page);

		if (((caddr_t)cd->buffer >= curr_page_addr) &&
		    ((caddr_t)cd->buffer <  curr_page_addr + PAGE_SIZE))
			break;
	}

	if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) {
		/* encode entry in current page */

		p = encode_entry_baggage(cd, p, name, namlen, ino);

		if (plus)
			p = encode_entryplus_baggage(cd, p, name, namlen, ino);
		num_entry_words = p - cd->buffer;
	} else if (*(page+1) != NULL) {
		/* temporarily encode entry into next page, then move back to
		 * current and next page in rq_respages[] */
		__be32 *p1, *tmp;
		int len1, len2;

		/* grab next page for temporary storage of entry */
		p1 = tmp = page_address(*(page+1));

		p1 = encode_entry_baggage(cd, p1, name, namlen, ino);

		if (plus)
			p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino);

		/* determine entry word length and lengths to go in pages */
		num_entry_words = p1 - tmp;
		len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer;
		if ((num_entry_words << 2) < len1) {
			/* the actual number of words in the entry is less
			 * than elen and can still fit in the current page
			 */
			memmove(p, tmp, num_entry_words << 2);
			p += num_entry_words;

			/* update offset */
			cd->offset = cd->buffer + (cd->offset - tmp);
		} else {
			unsigned int offset_r = (cd->offset - tmp) << 2;

			/* update pointer to offset location.
			 * This is a 64bit quantity, so we need to
			 * deal with 3 cases:
			 *  -	entirely in first page
			 *  -	entirely in second page
			 *  -	4 bytes in each page
			 */
			if (offset_r + 8 <= len1) {
				cd->offset = p + (cd->offset - tmp);
			} else if (offset_r >= len1) {
				cd->offset -= len1 >> 2;
			} else {
				/* sitting on the fence */
				BUG_ON(offset_r != len1 - 4);
				cd->offset = p + (cd->offset - tmp);
				cd->offset1 = tmp;
			}

			len2 = (num_entry_words << 2) - len1;

			/* move from temp page to current and next pages */
			memmove(p, tmp, len1);
			memmove(tmp, (caddr_t)tmp+len1, len2);

			p = tmp + (len2 >> 2);
		}
	}
	else {
		cd->common.err = nfserr_toosmall;
		return -EINVAL;
	}

	cd->buflen -= num_entry_words;
	cd->buffer = p;
	cd->common.err = nfs_ok;
	return 0;

}


nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p,
					struct nfsd3_linkres *resp)
{
	p = encode_post_op_attr(rqstp, p, &resp->fh);
	p = encode_wcc_data(rqstp, p, &resp->tfh);
	return xdr_ressize_check(rqstp, p);
}


encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
	      struct kstat *stat)
{
	*p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
	*p++ = htonl((u32) (stat->mode & S_IALLUGO));
	*p++ = htonl((u32) stat->nlink);
	*p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
	*p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
	if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
	} else {
		p = xdr_encode_hyper(p, (u64) stat->size);
	}
	p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
	*p++ = htonl((u32) MAJOR(stat->rdev));
	*p++ = htonl((u32) MINOR(stat->rdev));
	p = encode_fsid(p, fhp);
	p = xdr_encode_hyper(p, stat->ino);
	p = encode_time3(p, &stat->atime);
	p = encode_time3(p, &stat->mtime);
	p = encode_time3(p, &stat->ctime);

	return p;
}


nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p,
					struct nfsd3_fsinfores *resp)
{
	*p++ = xdr_zero;	/* no post_op_attr */

	if (resp->status == 0) {
		*p++ = htonl(resp->f_rtmax);
		*p++ = htonl(resp->f_rtpref);
		*p++ = htonl(resp->f_rtmult);
		*p++ = htonl(resp->f_wtmax);
		*p++ = htonl(resp->f_wtpref);
		*p++ = htonl(resp->f_wtmult);
		*p++ = htonl(resp->f_dtpref);
		p = xdr_encode_hyper(p, resp->f_maxfilesize);
		*p++ = xdr_one;
		*p++ = xdr_zero;
		*p++ = htonl(resp->f_properties);
	}

	return xdr_ressize_check(rqstp, p);
}


struct key *rxrpc_get_null_key(const char *keyname)
{
	const struct cred *cred = current_cred();
	struct key *key;
	int ret;

	key = key_alloc(&key_type_rxrpc, keyname,
			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL);
	if (IS_ERR(key))
		return key;

	ret = key_instantiate_and_link(key, NULL, 0, NULL, NULL);
	if (ret < 0) {
		key_revoke(key);
		key_put(key);
		return ERR_PTR(ret);
	}

	return key;
}


static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep,
				   size_t datalen,
				   const __be32 *xdr, unsigned int toklen)
{
	struct rxrpc_key_token *token, **pptoken;
	struct rxk5_key *rxk5;
	const __be32 *end_xdr = xdr + (toklen >> 2);
	int ret;

	_enter(",{%x,%x,%x,%x},%u",
	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
	       toklen);

	/* reserve some payload space for this subkey - the length of the token
	 * is a reasonable approximation */
	prep->quotalen = datalen + toklen;

	token = kzalloc(sizeof(*token), GFP_KERNEL);
	if (!token)
		return -ENOMEM;

	rxk5 = kzalloc(sizeof(*rxk5), GFP_KERNEL);
	if (!rxk5) {
		kfree(token);
		return -ENOMEM;
	}

	token->security_index = RXRPC_SECURITY_RXK5;
	token->k5 = rxk5;

	/* extract the principals */
	ret = rxrpc_krb5_decode_principal(&rxk5->client, &xdr, &toklen);
	if (ret < 0)
		goto error;
	ret = rxrpc_krb5_decode_principal(&rxk5->server, &xdr, &toklen);
	if (ret < 0)
		goto error;

	/* extract the session key and the encoding type (the tag field ->
	 * ENCTYPE_xxx) */
	ret = rxrpc_krb5_decode_tagged_data(&rxk5->session, AFSTOKEN_DATA_MAX,
					    &xdr, &toklen);
	if (ret < 0)
		goto error;

	if (toklen < 4 * 8 + 2 * 4)
		goto inval;
	rxk5->authtime	= be64_to_cpup((const __be64 *) xdr);
	xdr += 2;
	rxk5->starttime	= be64_to_cpup((const __be64 *) xdr);
	xdr += 2;
	rxk5->endtime	= be64_to_cpup((const __be64 *) xdr);
	xdr += 2;
	rxk5->renew_till = be64_to_cpup((const __be64 *) xdr);
	xdr += 2;
	rxk5->is_skey = ntohl(*xdr++);
	rxk5->flags = ntohl(*xdr++);
	toklen -= 4 * 8 + 2 * 4;

	_debug("times: a=%llx s=%llx e=%llx rt=%llx",
	       rxk5->authtime, rxk5->starttime, rxk5->endtime,
	       rxk5->renew_till);
	_debug("is_skey=%x flags=%x", rxk5->is_skey, rxk5->flags);

	/* extract the permitted client addresses */
	ret = rxrpc_krb5_decode_tagged_array(&rxk5->addresses,
					     &rxk5->n_addresses,
					     AFSTOKEN_K5_ADDRESSES_MAX,
					     AFSTOKEN_DATA_MAX,
					     &xdr, &toklen);
	if (ret < 0)
		goto error;

	ASSERTCMP((end_xdr - xdr) << 2, ==, toklen);

	/* extract the tickets */
	ret = rxrpc_krb5_decode_ticket(&rxk5->ticket, &rxk5->ticket_len,
				       &xdr, &toklen);
	if (ret < 0)
		goto error;
	ret = rxrpc_krb5_decode_ticket(&rxk5->ticket2, &rxk5->ticket2_len,
				       &xdr, &toklen);
	if (ret < 0)
		goto error;

	ASSERTCMP((end_xdr - xdr) << 2, ==, toklen);

	/* extract the typed auth data */
	ret = rxrpc_krb5_decode_tagged_array(&rxk5->authdata,
					     &rxk5->n_authdata,
					     AFSTOKEN_K5_AUTHDATA_MAX,
					     AFSTOKEN_BDATALN_MAX,
					     &xdr, &toklen);
	if (ret < 0)
		goto error;

	ASSERTCMP((end_xdr - xdr) << 2, ==, toklen);

	if (toklen != 0)
		goto inval;

	/* attach the payload */
	for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
	     *pptoken;
	     pptoken = &(*pptoken)->next)
		continue;
	*pptoken = token;
	if (token->kad->expiry < prep->expiry)
		prep->expiry = token->kad->expiry;

	_leave(" = 0");
	return 0;

inval:
	ret = -EINVAL;
error:
	rxrpc_rxk5_free(rxk5);
	kfree(token);
	_leave(" = %d", ret);
	return ret;
}


list_del_event(struct perf_event *event, struct perf_event_context *ctx)
{
	struct perf_cpu_context *cpuctx;
	/*
	 * We can have double detach due to exit/hot-unplug + close.
	 */
	if (!(event->attach_state & PERF_ATTACH_CONTEXT))
		return;

	event->attach_state &= ~PERF_ATTACH_CONTEXT;

	if (is_cgroup_event(event)) {
		ctx->nr_cgroups--;
		cpuctx = __get_cpu_context(ctx);
		/*
		 * if there are no more cgroup events
		 * then cler cgrp to avoid stale pointer
		 * in update_cgrp_time_from_cpuctx()
		 */
		if (!ctx->nr_cgroups)
			cpuctx->cgrp = NULL;
	}

	if (has_branch_stack(event))
		ctx->nr_branch_stack--;

	ctx->nr_events--;
	if (event->attr.inherit_stat)
		ctx->nr_stat--;

	list_del_rcu(&event->event_entry);

	if (event->group_leader == event)
		list_del_init(&event->group_entry);

	update_group_times(event);

	/*
	 * If event was in error state, then keep it
	 * that way, otherwise bogus counts will be
	 * returned on read(). The only way to get out
	 * of error state is by explicit re-enabling
	 * of the event
	 */
	if (event->state > PERF_EVENT_STATE_OFF)
		event->state = PERF_EVENT_STATE_OFF;

	ctx->generation++;
}


const char *ipx_frame_name(__be16 frame)
{
	char* rc = "None";

	switch (ntohs(frame)) {
	case ETH_P_IPX:		rc = "EtherII";	break;
	case ETH_P_802_2:	rc = "802.2";	break;
	case ETH_P_SNAP:	rc = "SNAP";	break;
	case ETH_P_802_3:	rc = "802.3";	break;
	}

	return rc;
}


static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
			int *uaddr_len, int peer)
{
	struct ipx_address *addr;
	struct sockaddr_ipx sipx;
	struct sock *sk = sock->sk;
	struct ipx_sock *ipxs = ipx_sk(sk);
	int rc;

	*uaddr_len = sizeof(struct sockaddr_ipx);

	lock_sock(sk);
	if (peer) {
		rc = -ENOTCONN;
		if (sk->sk_state != TCP_ESTABLISHED)
			goto out;

		addr = &ipxs->dest_addr;
		sipx.sipx_network	= addr->net;
		sipx.sipx_port		= addr->sock;
		memcpy(sipx.sipx_node, addr->node, IPX_NODE_LEN);
	} else {
		if (ipxs->intrfc) {
			sipx.sipx_network = ipxs->intrfc->if_netnum;
#ifdef CONFIG_IPX_INTERN
			memcpy(sipx.sipx_node, ipxs->node, IPX_NODE_LEN);
#else
			memcpy(sipx.sipx_node, ipxs->intrfc->if_node,
				IPX_NODE_LEN);
#endif	/* CONFIG_IPX_INTERN */

		} else {
			sipx.sipx_network = 0;
			memset(sipx.sipx_node, '\0', IPX_NODE_LEN);
		}

		sipx.sipx_port = ipxs->port;
	}

	sipx.sipx_family = AF_IPX;
	sipx.sipx_type	 = ipxs->type;
	sipx.sipx_zero	 = 0;
	memcpy(uaddr, &sipx, sizeof(sipx));

	rc = 0;
out:
	release_sock(sk);
	return rc;
}


static int ipxitf_add_local_route(struct ipx_interface *intrfc)
{
	return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL);
}


static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc,
						unsigned char *ipx_node,
						__be16 port)
{
	struct sock *s;

	ipxitf_hold(intrfc);
	spin_lock_bh(&intrfc->if_sklist_lock);

	sk_for_each(s, &intrfc->if_sklist) {
		struct ipx_sock *ipxs = ipx_sk(s);

		if (ipxs->port == port &&
		    !memcmp(ipx_node, ipxs->node, IPX_NODE_LEN))
			goto found;
	}
	s = NULL;
found:
	spin_unlock_bh(&intrfc->if_sklist_lock);
	ipxitf_put(intrfc);
	return s;
}


static int __ipx_bind(struct socket *sock,
			struct sockaddr *uaddr, int addr_len)
{
	struct sock *sk = sock->sk;
	struct ipx_sock *ipxs = ipx_sk(sk);
	struct ipx_interface *intrfc;
	struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr;
	int rc = -EINVAL;

	if (!sock_flag(sk, SOCK_ZAPPED) || addr_len != sizeof(struct sockaddr_ipx))
		goto out;

	intrfc = ipxitf_find_using_net(addr->sipx_network);
	rc = -EADDRNOTAVAIL;
	if (!intrfc)
		goto out;

	if (!addr->sipx_port) {
		addr->sipx_port = ipx_first_free_socketnum(intrfc);
		rc = -EINVAL;
		if (!addr->sipx_port)
			goto out_put;
	}

	/* protect IPX system stuff like routing/sap */
	rc = -EACCES;
	if (ntohs(addr->sipx_port) < IPX_MIN_EPHEMERAL_SOCKET &&
	    !capable(CAP_NET_ADMIN))
		goto out_put;

	ipxs->port = addr->sipx_port;

#ifdef CONFIG_IPX_INTERN
	if (intrfc == ipx_internal_net) {
		/* The source address is to be set explicitly if the
		 * socket is to be bound on the internal network. If a
		 * node number 0 was specified, the default is used.
		 */

		rc = -EINVAL;
		if (!memcmp(addr->sipx_node, ipx_broadcast_node, IPX_NODE_LEN))
			goto out_put;
		if (!memcmp(addr->sipx_node, ipx_this_node, IPX_NODE_LEN))
			memcpy(ipxs->node, intrfc->if_node, IPX_NODE_LEN);
		else
			memcpy(ipxs->node, addr->sipx_node, IPX_NODE_LEN);

		rc = -EADDRINUSE;
		if (ipxitf_find_internal_socket(intrfc, ipxs->node,
						ipxs->port)) {
			SOCK_DEBUG(sk,
				"IPX: bind failed because port %X in use.\n",
				ntohs(addr->sipx_port));
			goto out_put;
		}
	} else {
		/* Source addresses are easy. It must be our
		 * network:node pair for an interface routed to IPX
		 * with the ipx routing ioctl()
		 */

		memcpy(ipxs->node, intrfc->if_node, IPX_NODE_LEN);

		rc = -EADDRINUSE;
		if (ipxitf_find_socket(intrfc, addr->sipx_port)) {
			SOCK_DEBUG(sk,
				"IPX: bind failed because port %X in use.\n",
				ntohs(addr->sipx_port));
			goto out_put;
		}
	}

#else	/* !def CONFIG_IPX_INTERN */

	/* Source addresses are easy. It must be our network:node pair for
	   an interface routed to IPX with the ipx routing ioctl() */

	rc = -EADDRINUSE;
	if (ipxitf_find_socket(intrfc, addr->sipx_port)) {
		SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n",
				ntohs((int)addr->sipx_port));
		goto out_put;
	}

#endif	/* CONFIG_IPX_INTERN */

	ipxitf_insert_socket(intrfc, sk);
	sock_reset_flag(sk, SOCK_ZAPPED);

	rc = 0;
out_put:
	ipxitf_put(intrfc);
out:
	return rc;
}


static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
						      __be16 datalink)
{
	struct ipx_interface *i;

	list_for_each_entry(i, &ipx_interfaces, node)
		if (i->if_dev == dev && i->if_dlink_type == datalink)
			goto out;
	i = NULL;
out:
	return i;
}


static int ipx_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
		       int flags)
{
	struct sock *sk = sock->sk;
	struct ipx_sock *ipxs = ipx_sk(sk);
	DECLARE_SOCKADDR(struct sockaddr_ipx *, sipx, msg->msg_name);
	struct ipxhdr *ipx = NULL;
	struct sk_buff *skb;
	int copied, rc;
	bool locked = true;

	lock_sock(sk);
	/* put the autobinding in */
	if (!ipxs->port) {
		struct sockaddr_ipx uaddr;

		uaddr.sipx_port		= 0;
		uaddr.sipx_network 	= 0;

#ifdef CONFIG_IPX_INTERN
		rc = -ENETDOWN;
		if (!ipxs->intrfc)
			goto out; /* Someone zonked the iface */
		memcpy(uaddr.sipx_node, ipxs->intrfc->if_node, IPX_NODE_LEN);
#endif	/* CONFIG_IPX_INTERN */

		rc = __ipx_bind(sock, (struct sockaddr *)&uaddr,
			      sizeof(struct sockaddr_ipx));
		if (rc)
			goto out;
	}

	rc = -ENOTCONN;
	if (sock_flag(sk, SOCK_ZAPPED))
		goto out;

	release_sock(sk);
	locked = false;
	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
				flags & MSG_DONTWAIT, &rc);
	if (!skb) {
		if (rc == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN))
			rc = 0;
		goto out;
	}

	ipx 	= ipx_hdr(skb);
	copied 	= ntohs(ipx->ipx_pktsize) - sizeof(struct ipxhdr);
	if (copied > size) {
		copied = size;
		msg->msg_flags |= MSG_TRUNC;
	}

	rc = skb_copy_datagram_msg(skb, sizeof(struct ipxhdr), msg, copied);
	if (rc)
		goto out_free;
	if (skb->tstamp)
		sk->sk_stamp = skb->tstamp;

	if (sipx) {
		sipx->sipx_family	= AF_IPX;
		sipx->sipx_port		= ipx->ipx_source.sock;
		memcpy(sipx->sipx_node, ipx->ipx_source.node, IPX_NODE_LEN);
		sipx->sipx_network	= IPX_SKB_CB(skb)->ipx_source_net;
		sipx->sipx_type 	= ipx->ipx_type;
		sipx->sipx_zero		= 0;
		msg->msg_namelen	= sizeof(*sipx);
	}
	rc = copied;

out_free:
	skb_free_datagram(sk, skb);
out:
	if (locked)
		release_sock(sk);
	return rc;
}


mailimf_unparsed_fields_parse(const char * message, size_t length,
			      size_t * indx,
			      struct mailimf_unparsed_fields ** result)
{
  size_t cur_token;
  clist * list;
  struct mailimf_unparsed_fields * fields;
  int r;
  int res;

  cur_token = * indx;

  list = NULL;

  r = mailimf_struct_multiple_parse(message, length, &cur_token,
				    &list,
				    (mailimf_struct_parser *)
				    mailimf_optional_field_parse,
				    (mailimf_struct_destructor *)
				    mailimf_optional_field_free);
  /*
  if ((r = MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
    res = r;
    goto err;
  }
  */

  switch (r) {
  case MAILIMF_NO_ERROR:
    /* do nothing */
    break;

  case MAILIMF_ERROR_PARSE:
    list = clist_new();
    if (list == NULL) {
      res = MAILIMF_ERROR_MEMORY;
      goto err;
    }
    break;

  default:
    res = r;
    goto err;
  }

  fields = mailimf_unparsed_fields_new(list);
  if (fields == NULL) {
    res = MAILIMF_ERROR_MEMORY;
    goto free;
  }

  * result = fields;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;

 free:
  if (list != NULL) {
    clist_foreach(list, (clist_func) mailimf_optional_field_free, NULL);
    clist_free(list);
  }
 err:
  return res;
}


int mailimf_ignore_field_parse(const char * message, size_t length,
			       size_t * indx)
{
  int has_field;
  size_t cur_token;
  int state;
  size_t terminal;

  has_field = FALSE;
  cur_token = * indx;

  terminal = cur_token;
  state = UNSTRUCTURED_START;

  /* check if this is not a beginning CRLF */

  if (cur_token >= length)
    return MAILIMF_ERROR_PARSE;

  switch (message[cur_token]) {
  case '\r':
    return MAILIMF_ERROR_PARSE;
  case '\n':
    return MAILIMF_ERROR_PARSE;
  }

  while (state != UNSTRUCTURED_OUT) {

    switch(state) {
    case UNSTRUCTURED_START:
      if (cur_token >= length)
	return MAILIMF_ERROR_PARSE;

      switch(message[cur_token]) {
      case '\r':
	state = UNSTRUCTURED_CR;
	break;
      case '\n':
	state = UNSTRUCTURED_LF;
	break;
      case ':':
	has_field = TRUE;
	state = UNSTRUCTURED_START;
	break;
      default:
	state = UNSTRUCTURED_START;
	break;
      }
      break;
    case UNSTRUCTURED_CR:
      if (cur_token >= length)
	return MAILIMF_ERROR_PARSE;

      switch(message[cur_token]) {
      case '\n':
	state = UNSTRUCTURED_LF;
	break;
      case ':':
	has_field = TRUE;
	state = UNSTRUCTURED_START;
	break;
      default:
	state = UNSTRUCTURED_START;
	break;
      }
      break;
    case UNSTRUCTURED_LF:
      if (cur_token >= length) {
	terminal = cur_token;
	state = UNSTRUCTURED_OUT;
	break;
      }

      switch(message[cur_token]) {
      case '\t':
      case ' ':
	state = UNSTRUCTURED_WSP;
	break;
      default:
	terminal = cur_token;
	state = UNSTRUCTURED_OUT;
	break;
      }
      break;
    case UNSTRUCTURED_WSP:
      if (cur_token >= length)
	return MAILIMF_ERROR_PARSE;

      switch(message[cur_token]) {
      case '\r':
	state = UNSTRUCTURED_CR;
	break;
      case '\n':
	state = UNSTRUCTURED_LF;
	break;
      case ':':
	has_field = TRUE;
	state = UNSTRUCTURED_START;
	break;
      default:
	state = UNSTRUCTURED_START;
	break;
      }
      break;
    }

    cur_token ++;
  }

  if (!has_field)
    return MAILIMF_ERROR_PARSE;

  * indx = terminal;

  return MAILIMF_NO_ERROR;
}


mailimf_optional_fields_parse(const char * message, size_t length,
			      size_t * indx,
			      struct mailimf_fields ** result)
{
  size_t cur_token;
  clist * list;
  struct mailimf_fields * fields;
  int r;
  int res;

  cur_token = * indx;

  list = NULL;

  r = mailimf_struct_multiple_parse(message, length, &cur_token,
				    &list,
				    (mailimf_struct_parser *)
				    mailimf_only_optional_field_parse,
				    (mailimf_struct_destructor *)
				    mailimf_field_free);
  switch (r) {
  case MAILIMF_NO_ERROR:
    /* do nothing */
    break;

  case MAILIMF_ERROR_PARSE:
    list = clist_new();
    if (list == NULL) {
      res = MAILIMF_ERROR_MEMORY;
      goto err;
    }
    break;

  default:
    res = r;
    goto err;
  }

  fields = mailimf_fields_new(list);
  if (fields == NULL) {
    res = MAILIMF_ERROR_MEMORY;
    goto free;
  }

  * result = fields;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;

 free:
  if (list != NULL) {
    clist_foreach(list, (clist_func) mailimf_field_free, NULL);
    clist_free(list);
  }
 err:
  return res;
}


static int mailimf_domain_literal_parse(const char * message, size_t length,
					size_t * indx, char ** result)
{
  size_t cur_token;
  int len;
  int begin;
  char * domain_literal;
  int r;

  cur_token = * indx;

  r = mailimf_cfws_parse(message, length, &cur_token);
  if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
    return r;

  begin = cur_token;
  r = mailimf_obracket_parse(message, length, &cur_token);
  if (r != MAILIMF_NO_ERROR)
    return r;

  while (1) {
    r = mailimf_domain_literal_fws_dcontent_parse(message, length,
						  &cur_token);
    if (r == MAILIMF_NO_ERROR) {
      /* do nothing */
    }
    else if (r == MAILIMF_ERROR_PARSE)
      break;
    else
      return r;
  }

  r = mailimf_fws_parse(message, length, &cur_token);
  if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
    return r;

  r = mailimf_cbracket_parse(message, length, &cur_token);
  if (r != MAILIMF_NO_ERROR)
    return r;

  len = cur_token - begin;

  domain_literal = malloc(len + 1);
  if (domain_literal == NULL)
    return MAILIMF_ERROR_MEMORY;
  strncpy(domain_literal, message + begin, len);
  domain_literal[len] = '\0';

  * result = domain_literal;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;
}


static int mailimf_trace_parse(const char * message, size_t length,
			       size_t * indx,
			       struct mailimf_trace ** result)
{
  size_t cur_token;
  struct mailimf_return * return_path;
  clist * received_list;
  struct mailimf_trace * trace;
  int r;
  int res;

  cur_token = * indx;
  return_path = NULL;
  received_list = NULL;

  r = mailimf_return_parse(message, length, &cur_token, &return_path);
  if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
    res = r;
    goto err;
  }

  r = mailimf_struct_multiple_parse(message, length, &cur_token,
				    &received_list,
				    (mailimf_struct_parser *)
				    mailimf_received_parse,
				    (mailimf_struct_destructor *)
				    mailimf_received_free);
  if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
    res = r;
    goto err;
  }

  if ((received_list == NULL) && (return_path == NULL)) {
    res = MAILIMF_ERROR_PARSE;
    goto free_return;
  }

  trace = mailimf_trace_new(return_path, received_list);
  if (trace == NULL) {
    res = MAILIMF_ERROR_MEMORY;
    goto free_list;
  }

  * result = trace;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;

 free_list:
  clist_foreach(received_list, (clist_func) mailimf_received_free, NULL);
  clist_free(received_list);
 free_return:
  if (return_path != NULL)
    mailimf_return_free(return_path);
 err:
  return res;
}


mailimf_resent_field_parse(const char * message, size_t length,
			   size_t * indx,
			   struct mailimf_resent_field ** result)
{
  struct mailimf_orig_date * resent_date;
  struct mailimf_from * resent_from;
  struct mailimf_sender * resent_sender;
  struct mailimf_to* resent_to;
  struct mailimf_cc * resent_cc;
  struct mailimf_bcc * resent_bcc;
  struct mailimf_message_id * resent_msg_id;
  size_t cur_token;
  int type;
  struct mailimf_resent_field * resent_field;
  int r;
  int res;

  cur_token = * indx;

  resent_date = NULL;
  resent_from = NULL;
  resent_sender = NULL;
  resent_to = NULL;
  resent_cc = NULL;
  resent_bcc = NULL;
  resent_msg_id = NULL;

  type = guess_resent_header_type(message, length, cur_token);

  switch(type) {
  case MAILIMF_RESENT_FIELD_DATE:
    r = mailimf_resent_date_parse(message, length, &cur_token,
				  &resent_date);
    if (r != MAILIMF_NO_ERROR) {
      res = r;
      goto err;
    }
    break;
  case MAILIMF_RESENT_FIELD_FROM:
    r = mailimf_resent_from_parse(message, length, &cur_token,
				  &resent_from);
    if (r != MAILIMF_NO_ERROR) {
      res = r;
      goto err;
    }
    break;
  case MAILIMF_RESENT_FIELD_SENDER:
    r = mailimf_resent_sender_parse(message, length, &cur_token,
				    &resent_sender);
    if (r != MAILIMF_NO_ERROR) {
      res = r;
      goto err;
    }
    break;
  case MAILIMF_RESENT_FIELD_TO:
    r = mailimf_resent_to_parse(message, length, &cur_token,
				&resent_to);
    if (r != MAILIMF_NO_ERROR) {
      res = r;
      goto err;
    }
    break;
  case MAILIMF_RESENT_FIELD_CC:
    r= mailimf_resent_cc_parse(message, length, &cur_token,
			       &resent_cc);
    if (r != MAILIMF_NO_ERROR) {
      res = r;
      goto err;
    }
    break;
  case MAILIMF_RESENT_FIELD_BCC:
    r = mailimf_resent_bcc_parse(message, length, &cur_token,
				 &resent_bcc);
    if (r != MAILIMF_NO_ERROR) {
      res = r;
      goto err;
    }
    break;
  case MAILIMF_RESENT_FIELD_MSG_ID:
    r = mailimf_resent_msg_id_parse(message, length, &cur_token,
				    &resent_msg_id);
    if (r != MAILIMF_NO_ERROR) {
      res = r;
      goto err;
    }
    break;
  default:
    res = MAILIMF_ERROR_PARSE;
    goto err;
  }

  resent_field = mailimf_resent_field_new(type, resent_date,
					  resent_from, resent_sender,
					  resent_to, resent_cc,
					  resent_bcc, resent_msg_id);
  if (resent_field == NULL) {
    res = MAILIMF_ERROR_MEMORY;
    goto free_resent;
  }

  * result = resent_field;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;

 free_resent:
  if (resent_msg_id != NULL)
    mailimf_message_id_free(resent_msg_id);
  if (resent_bcc != NULL)
    mailimf_bcc_free(resent_bcc);
  if (resent_cc != NULL)
    mailimf_cc_free(resent_cc);
  if (resent_to != NULL)
    mailimf_to_free(resent_to);
  if (resent_sender != NULL)
    mailimf_sender_free(resent_sender);
  if (resent_from != NULL)
    mailimf_from_free(resent_from);
  if (resent_date != NULL)
    mailimf_orig_date_free(resent_date);
 err:
  return res;
}


static int mailimf_at_sign_parse(const char * message, size_t length,
				      size_t * indx)
{
  return mailimf_unstrict_char_parse(message, length, indx, '@');
}


int mailimf_body_parse(const char * message, size_t length,
		       size_t * indx,
		       struct mailimf_body ** result)
{
  size_t cur_token;
  struct mailimf_body * body;

  cur_token = * indx;

  body = mailimf_body_new(message + cur_token, length - cur_token);
  if (body == NULL)
    return MAILIMF_ERROR_MEMORY;

  cur_token = length;

  * result = body;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;
}


static int mailimf_addr_spec_parse(const char * message, size_t length,
				   size_t * indx,
				   char ** result)
{
  size_t cur_token;
#if 0
  char * local_part;
  char * domain;
#endif
  char * addr_spec;
  int r;
  int res;
  size_t begin;
  size_t end;
  int final;
  size_t count;
  const char * src;
  char * dest;
  size_t i;

  cur_token = * indx;

  r = mailimf_cfws_parse(message, length, &cur_token);
  if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
    res = r;
    goto err;
  }

  end = cur_token;
  if (end >= length) {
    res = MAILIMF_ERROR_PARSE;
    goto err;
  }

  begin = cur_token;

  final = FALSE;
  while (1) {
    switch (message[end]) {
    case '>':
    case ',':
    case '\r':
    case '\n':
    case '(':
    case ')':
    case ':':
    case ';':
      final = TRUE;
      break;
    }

    if (final)
      break;

    end ++;
    if (end >= length)
      break;
  }

  if (end == begin) {
    res = MAILIMF_ERROR_PARSE;
    goto err;
  }

  addr_spec = malloc(end - cur_token + 1);
  if (addr_spec == NULL) {
    res = MAILIMF_ERROR_MEMORY;
    goto err;
  }

  count = end - cur_token;
  src = message + cur_token;
  dest = addr_spec;
  for(i = 0 ; i < count ; i ++) {
    if ((* src != ' ') && (* src != '\t')) {
      * dest = * src;
      dest ++;
    }
    src ++;
  }
  * dest = '\0';

#if 0
  strncpy(addr_spec, message + cur_token, end - cur_token);
  addr_spec[end - cur_token] = '\0';
#endif

  cur_token = end;

#if 0
  r = mailimf_local_part_parse(message, length, &cur_token, &local_part);
  if (r != MAILIMF_NO_ERROR) {
    res = r;
    goto err;
  }

  r = mailimf_at_sign_parse(message, length, &cur_token);
  switch (r) {
  case MAILIMF_NO_ERROR:
    r = mailimf_domain_parse(message, length, &cur_token, &domain);
    if (r != MAILIMF_NO_ERROR) {
      res = r;
      goto free_local_part;
    }
    break;

  case MAILIMF_ERROR_PARSE:
    domain = NULL;
    break;

  default:
    res = r;
    goto free_local_part;
  }

  if (domain) {
    addr_spec = malloc(strlen(local_part) + strlen(domain) + 2);
    if (addr_spec == NULL) {
      res = MAILIMF_ERROR_MEMORY;
      goto free_domain;
    }

    strcpy(addr_spec, local_part);
    strcat(addr_spec, "@");
    strcat(addr_spec, domain);

    mailimf_domain_free(domain);
    mailimf_local_part_free(local_part);
  }
  else {
    addr_spec = local_part;
  }
#endif

  * result = addr_spec;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;

#if 0
 free_domain:
  mailimf_domain_free(domain);
 free_local_part:
  mailimf_local_part_free(local_part);
#endif
 err:
  return res;
}


int mailimf_address_parse(const char * message, size_t length,
			  size_t * indx,
			  struct mailimf_address ** result)
{
  int type;
  size_t cur_token;
  struct mailimf_mailbox * mailbox;
  struct mailimf_group * group;
  struct mailimf_address * address;
  int r;
  int res;

  cur_token = * indx;

  mailbox = NULL;
  group = NULL;

  type = MAILIMF_ADDRESS_ERROR; /* XXX - removes a gcc warning */
  r = mailimf_group_parse(message, length, &cur_token, &group);
  if (r == MAILIMF_NO_ERROR)
    type = MAILIMF_ADDRESS_GROUP;

  if (r == MAILIMF_ERROR_PARSE) {
    r = mailimf_mailbox_parse(message, length, &cur_token, &mailbox);
    if (r == MAILIMF_NO_ERROR)
      type = MAILIMF_ADDRESS_MAILBOX;
  }

  if (r != MAILIMF_NO_ERROR) {
    res = r;
    goto err;
  }

  address = mailimf_address_new(type, mailbox, group);
  if (address == NULL) {
    res = MAILIMF_ERROR_MEMORY;
    goto free;
  }

  * result = address;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;

 free:
  if (mailbox != NULL)
    mailimf_mailbox_free(mailbox);
  if (group != NULL)
    mailimf_group_free(group);
 err:
  return res;
}


static int mailimf_phrase_parse(const char * message, size_t length,
				size_t * indx, char ** result)
{
  MMAPString * gphrase;
  char * word;
  int first;
  size_t cur_token;
  int r;
  int res;
  char * str;
  int has_missing_closing_quote;

  cur_token = * indx;
  has_missing_closing_quote = 0;

  gphrase = mmap_string_new("");
  if (gphrase == NULL) {
    res = MAILIMF_ERROR_MEMORY;
    goto err;
  }

  first = TRUE;

  while (1) {
    int missing_quote = 0;
    r = mailimf_fws_word_parse(message, length, &cur_token, &word, &missing_quote);
    if (missing_quote) {
      has_missing_closing_quote = 1;
    }
    if (r == MAILIMF_NO_ERROR) {
      if (!first) {
	if (mmap_string_append_c(gphrase, ' ') == NULL) {
	  mailimf_word_free(word);
	  res = MAILIMF_ERROR_MEMORY;
	  goto free;
	}
      }
      if (mmap_string_append(gphrase, word) == NULL) {
	mailimf_word_free(word);
	res = MAILIMF_ERROR_MEMORY;
	goto free;
      }
      mailimf_word_free(word);
      first = FALSE;
    }
    else if (r == MAILIMF_ERROR_PARSE)
      break;
    else {
      res = r;
      goto free;
    }
  }

  if (first) {
    res = MAILIMF_ERROR_PARSE;
    goto free;
  }

  if (has_missing_closing_quote) {
    r = mailimf_char_parse(message, length, &cur_token, '\"');
  }

  str = strdup(gphrase->str);
  if (str == NULL) {
    res = MAILIMF_ERROR_MEMORY;
    goto free;
  }
  mmap_string_free(gphrase);

  * result = str;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;

 free:
  mmap_string_free(gphrase);
 err:
  return res;
}


static int mailimf_broken_date_parse(const char * message, size_t length,
                                     size_t * indx,
                                     int * pday, int * pmonth, int * pyear)
{
  size_t cur_token;
  int day;
  int month;
  int year;
  int r;

  cur_token = * indx;

  month = 1;
  r = mailimf_month_parse(message, length, &cur_token, &month);
  if (r != MAILIMF_NO_ERROR)
    return r;

  day = 1;
  r = mailimf_day_parse(message, length, &cur_token, &day);
  if (r != MAILIMF_NO_ERROR)
    return r;

  year = 2001;
  r = mailimf_year_parse(message, length, &cur_token, &year);
  if (r != MAILIMF_NO_ERROR)
    return r;

  * pday = day;
  * pmonth = month;
  * pyear = year;

  * indx = cur_token;

  return MAILIMF_NO_ERROR;
}


mailimf_only_optional_field_parse(const char * message,
				  size_t length,
				  size_t * indx,
				  struct mailimf_field ** result)
{
  int r;
  size_t cur_token;
  struct mailimf_optional_field * optional_field;
  struct mailimf_field * field;

  cur_token = * indx;

  r = mailimf_optional_field_parse(message, length, &cur_token,
				   &optional_field);
  if (r != MAILIMF_NO_ERROR)
    return r;

  field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, NULL, NULL,
      NULL, NULL, NULL, NULL, NULL,
      NULL, NULL, NULL, NULL, NULL,
      NULL, NULL, NULL, NULL, NULL,
      NULL, NULL, NULL, optional_field);
  if (field == NULL) {
    mailimf_optional_field_free(optional_field);
    return MAILIMF_ERROR_MEMORY;
  }

  * result = field;
  * indx = cur_token;

  return MAILIMF_NO_ERROR;
}


static int regulator_ena_gpio_request(struct regulator_dev *rdev,
				const struct regulator_config *config)
{
	struct regulator_enable_gpio *pin;
	struct gpio_desc *gpiod;
	int ret;

	gpiod = gpio_to_desc(config->ena_gpio);

	list_for_each_entry(pin, &regulator_ena_gpio_list, list) {
		if (pin->gpiod == gpiod) {
			rdev_dbg(rdev, "GPIO %d is already used\n",
				config->ena_gpio);
			goto update_ena_gpio_to_rdev;
		}
	}

	ret = gpio_request_one(config->ena_gpio,
				GPIOF_DIR_OUT | config->ena_gpio_flags,
				rdev_get_name(rdev));
	if (ret)
		return ret;

	pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL);
	if (pin == NULL) {
		gpio_free(config->ena_gpio);
		return -ENOMEM;
	}

	pin->gpiod = gpiod;
	pin->ena_gpio_invert = config->ena_gpio_invert;
	list_add(&pin->list, &regulator_ena_gpio_list);

update_ena_gpio_to_rdev:
	pin->request_count++;
	rdev->ena_pin = pin;
	return 0;
}


int regulator_is_supported_voltage(struct regulator *regulator,
				   int min_uV, int max_uV)
{
	struct regulator_dev *rdev = regulator->rdev;
	int i, voltages, ret;

	/* If we can't change voltage check the current voltage */
	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
		ret = regulator_get_voltage(regulator);
		if (ret >= 0)
			return min_uV <= ret && ret <= max_uV;
		else
			return ret;
	}

	/* Any voltage within constrains range is fine? */
	if (rdev->desc->continuous_voltage_range)
		return min_uV >= rdev->constraints->min_uV &&
				max_uV <= rdev->constraints->max_uV;

	ret = regulator_count_voltages(regulator);
	if (ret < 0)
		return ret;
	voltages = ret;

	for (i = 0; i < voltages; i++) {
		ret = regulator_list_voltage(regulator, i);

		if (ret >= min_uV && ret <= max_uV)
			return 1;
	}

	return 0;
}


static ssize_t regulator_suspend_disk_state_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct regulator_dev *rdev = dev_get_drvdata(dev);

	return regulator_print_state(buf,
			rdev->constraints->state_disk.enabled);
}


static int regulator_check_current_limit(struct regulator_dev *rdev,
					int *min_uA, int *max_uA)
{
	BUG_ON(*min_uA > *max_uA);

	if (!rdev->constraints) {
		rdev_err(rdev, "no constraints\n");
		return -ENODEV;
	}
	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
		rdev_err(rdev, "operation not allowed\n");
		return -EPERM;
	}

	if (*max_uA > rdev->constraints->max_uA)
		*max_uA = rdev->constraints->max_uA;
	if (*min_uA < rdev->constraints->min_uA)
		*min_uA = rdev->constraints->min_uA;

	if (*min_uA > *max_uA) {
		rdev_err(rdev, "unsupportable current range: %d-%duA\n",
			 *min_uA, *max_uA);
		return -EINVAL;
	}

	return 0;
}


static ssize_t regulator_print_opmode(char *buf, int mode)
{
	switch (mode) {
	case REGULATOR_MODE_FAST:
		return sprintf(buf, "fast\n");
	case REGULATOR_MODE_NORMAL:
		return sprintf(buf, "normal\n");
	case REGULATOR_MODE_IDLE:
		return sprintf(buf, "idle\n");
	case REGULATOR_MODE_STANDBY:
		return sprintf(buf, "standby\n");
	}
	return sprintf(buf, "unknown\n");
}


int regulator_suspend_finish(void)
{
	struct regulator_dev *rdev;
	int ret = 0, error;

	mutex_lock(&regulator_list_mutex);
	list_for_each_entry(rdev, &regulator_list, list) {
		mutex_lock(&rdev->mutex);
		if (rdev->use_count > 0  || rdev->constraints->always_on) {
			error = _regulator_do_enable(rdev);
			if (error)
				ret = error;
		} else {
			if (!have_full_constraints())
				goto unlock;
			if (!_regulator_is_enabled(rdev))
				goto unlock;

			error = _regulator_do_disable(rdev);
			if (error)
				ret = error;
		}
unlock:
		mutex_unlock(&rdev->mutex);
	}
	mutex_unlock(&regulator_list_mutex);
	return ret;
}


int regulator_get_voltage(struct regulator *regulator)
{
	int ret;

	mutex_lock(&regulator->rdev->mutex);

	ret = _regulator_get_voltage(regulator->rdev);

	mutex_unlock(&regulator->rdev->mutex);

	return ret;
}


int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
				   unsigned int old_selector,
				   unsigned int new_selector)
{
	unsigned int ramp_delay = 0;
	int old_volt, new_volt;

	if (rdev->constraints->ramp_delay)
		ramp_delay = rdev->constraints->ramp_delay;
	else if (rdev->desc->ramp_delay)
		ramp_delay = rdev->desc->ramp_delay;

	if (ramp_delay == 0) {
		rdev_warn(rdev, "ramp_delay not set\n");
		return 0;
	}

	/* sanity check */
	if (!rdev->desc->ops->list_voltage)
		return -EINVAL;

	old_volt = rdev->desc->ops->list_voltage(rdev, old_selector);
	new_volt = rdev->desc->ops->list_voltage(rdev, new_selector);

	return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
}


static int set_consumer_device_supply(struct regulator_dev *rdev,
				      const char *consumer_dev_name,
				      const char *supply)
{
	struct regulator_map *node;
	int has_dev;

	if (supply == NULL)
		return -EINVAL;

	if (consumer_dev_name != NULL)
		has_dev = 1;
	else
		has_dev = 0;

	list_for_each_entry(node, &regulator_map_list, list) {
		if (node->dev_name && consumer_dev_name) {
			if (strcmp(node->dev_name, consumer_dev_name) != 0)
				continue;
		} else if (node->dev_name || consumer_dev_name) {
			continue;
		}

		if (strcmp(node->supply, supply) != 0)
			continue;

		pr_debug("%s: %s/%s is '%s' supply; fail %s/%s\n",
			 consumer_dev_name,
			 dev_name(&node->regulator->dev),
			 node->regulator->desc->name,
			 supply,
			 dev_name(&rdev->dev), rdev_get_name(rdev));
		return -EBUSY;
	}

	node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
	if (node == NULL)
		return -ENOMEM;

	node->regulator = rdev;
	node->supply = supply;

	if (has_dev) {
		node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
		if (node->dev_name == NULL) {
			kfree(node);
			return -ENOMEM;
		}
	}

	list_add(&node->list, &regulator_map_list);
	return 0;
}


static ssize_t regulator_min_uA_show(struct device *dev,
				    struct device_attribute *attr, char *buf)
{
	struct regulator_dev *rdev = dev_get_drvdata(dev);

	if (!rdev->constraints)
		return sprintf(buf, "constraint not defined\n");

	return sprintf(buf, "%d\n", rdev->constraints->min_uA);
}


static void _regulator_put(struct regulator *regulator)
{
	struct regulator_dev *rdev;

	if (regulator == NULL || IS_ERR(regulator))
		return;

	rdev = regulator->rdev;

	debugfs_remove_recursive(regulator->debugfs);

	/* remove any sysfs entries */
	if (regulator->dev)
		sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
	kfree(regulator->supply_name);
	list_del(&regulator->list);
	kfree(regulator);

	rdev->open_count--;
	rdev->exclusive = 0;

	module_put(rdev->owner);
}


static void drms_uA_update(struct regulator_dev *rdev)
{
	struct regulator *sibling;
	int current_uA = 0, output_uV, input_uV, err;
	unsigned int mode;

	err = regulator_check_drms(rdev);
	if (err < 0 || !rdev->desc->ops->get_optimum_mode ||
	    (!rdev->desc->ops->get_voltage &&
	     !rdev->desc->ops->get_voltage_sel) ||
	    !rdev->desc->ops->set_mode)
		return;

	/* get output voltage */
	output_uV = _regulator_get_voltage(rdev);
	if (output_uV <= 0)
		return;

	/* get input voltage */
	input_uV = 0;
	if (rdev->supply)
		input_uV = regulator_get_voltage(rdev->supply);
	if (input_uV <= 0)
		input_uV = rdev->constraints->input_uV;
	if (input_uV <= 0)
		return;

	/* calc total requested load */
	list_for_each_entry(sibling, &rdev->consumer_list, list)
		current_uA += sibling->uA_load;

	/* now get the optimum mode for our new total regulator load */
	mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV,
						  output_uV, current_uA);

	/* check the new mode is allowed */
	err = regulator_mode_constrain(rdev, &mode);
	if (err == 0)
		rdev->desc->ops->set_mode(rdev, mode);
}


static ssize_t regulator_bypass_show(struct device *dev,
				     struct device_attribute *attr, char *buf)
{
	struct regulator_dev *rdev = dev_get_drvdata(dev);
	const char *report;
	bool bypass;
	int ret;

	ret = rdev->desc->ops->get_bypass(rdev, &bypass);

	if (ret != 0)
		report = "unknown";
	else if (bypass)
		report = "enabled";
	else
		report = "disabled";

	return sprintf(buf, "%s\n", report);
}


void regulator_unregister_supply_alias(struct device *dev, const char *id)
{
	struct regulator_supply_alias *map;

	map = regulator_find_supply_alias(dev, id);
	if (map) {
		list_del(&map->list);
		kfree(map);
	}
}


void Smb4KMountJob::slotFinishJob()
{
  QMutableListIterator<Smb4KShare *> it( m_shares );
  Smb4KShare *share = NULL;

  while ( it.hasNext() )
  {
    share = it.next();

    // Check which share has been mounted and emit the mounted() signal
    // if appropriate.
    if ( !share->isMounted() )
    {
      KMountPoint::List mount_points = KMountPoint::currentMountPoints( KMountPoint::BasicInfoNeeded|KMountPoint::NeedMountOptions );

      for ( int i = 0; i < mount_points.size(); ++i )
      {
        if ( QString::compare( mount_points.at( i )->mountPoint(), share->path() ) == 0 ||
             QString::compare( mount_points.at( i )->mountPoint(), share->canonicalPath() ) == 0 )
        {
          share->setIsMounted( true );
          emit mounted( share );
          break;
        }
        else
        {
          continue;
        }
      }
    }
    else
    {
      // Do nothing
    }
  }

  // Emit result() signal and tell the job to finish.
  emitResult();
  emit finished( m_shares );
}


cr_tknzr_peek_char (CRTknzr * a_this, guint32 * a_char)
{
        g_return_val_if_fail (a_this && PRIVATE (a_this)
                              && PRIVATE (a_this)->input
                              && a_char, CR_BAD_PARAM_ERROR);

        if (PRIVATE (a_this)->token_cache) {
                cr_input_set_cur_pos (PRIVATE (a_this)->input,
                                      &PRIVATE (a_this)->prev_pos);
                cr_token_destroy (PRIVATE (a_this)->token_cache);
                PRIVATE (a_this)->token_cache = NULL;
        }

        return cr_input_peek_char (PRIVATE (a_this)->input, a_char);
}


cr_tknzr_get_nb_bytes_left (CRTknzr * a_this)
{
        g_return_val_if_fail (a_this && PRIVATE (a_this)
                              && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);

        if (PRIVATE (a_this)->token_cache) {
                cr_input_set_cur_pos (PRIVATE (a_this)->input,
                                      &PRIVATE (a_this)->prev_pos);
                cr_token_destroy (PRIVATE (a_this)->token_cache);
                PRIVATE (a_this)->token_cache = NULL;
        }

        return cr_input_get_nb_bytes_left (PRIVATE (a_this)->input);
}


cr_tknzr_parse_important (CRTknzr * a_this,
                          CRParsingLocation *a_location)
{
        guint32 cur_char = 0;
        CRInputPos init_pos;
        enum CRStatus status = CR_OK;

        g_return_val_if_fail (a_this && PRIVATE (a_this)
                              && PRIVATE (a_this)->input,
                              CR_BAD_PARAM_ERROR);

        RECORD_INITIAL_POS (a_this, &init_pos);
        READ_NEXT_CHAR (a_this, &cur_char);
        ENSURE_PARSING_COND (cur_char == '!');
        if (a_location) {
                cr_tknzr_get_parsing_location (a_this,
                                               a_location) ;
        }
        cr_tknzr_try_to_skip_spaces (a_this);

        if (BYTE (PRIVATE (a_this)->input, 1, NULL) == 'i'
            && BYTE (PRIVATE (a_this)->input, 2, NULL) == 'm'
            && BYTE (PRIVATE (a_this)->input, 3, NULL) == 'p'
            && BYTE (PRIVATE (a_this)->input, 4, NULL) == 'o'
            && BYTE (PRIVATE (a_this)->input, 5, NULL) == 'r'
            && BYTE (PRIVATE (a_this)->input, 6, NULL) == 't'
            && BYTE (PRIVATE (a_this)->input, 7, NULL) == 'a'
            && BYTE (PRIVATE (a_this)->input, 8, NULL) == 'n'
            && BYTE (PRIVATE (a_this)->input, 9, NULL) == 't') {
                SKIP_BYTES (a_this, 9);
                if (a_location) {
                        cr_tknzr_get_parsing_location (a_this,
                                                       a_location) ;
                }
                return CR_OK;
        } else {
                status = CR_PARSING_ERROR;
        }

 error:
        cr_tknzr_set_cur_pos (a_this, &init_pos);

        return status;
}