Ejemplo n.º 1
0
/*
 * Handle control operations.
 */
static int
tweioctl(dev_t dev, u_long cmd, void *data, int flag,
    struct lwp *l)
{
	struct twe_softc *twe;
	struct twe_ccb *ccb;
	struct twe_param *param;
	struct twe_usercommand *tu;
	struct twe_paramcommand *tp;
	struct twe_drivecommand *td;
	void *pdata = NULL;
	int s, error = 0;
	u_int8_t cmdid;

	twe = device_lookup_private(&twe_cd, minor(dev));
	tu = (struct twe_usercommand *)data;
	tp = (struct twe_paramcommand *)data;
	td = (struct twe_drivecommand *)data;

	/* This is intended to be compatible with the FreeBSD interface. */
	switch (cmd) {
	case TWEIO_COMMAND:
		error = kauth_authorize_device_passthru(l->l_cred, dev,
		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data);
		if (error)
			return (error);

		/* XXX mutex */
		if (tu->tu_size > 0) {
			/*
			 * XXX Handle > TWE_SECTOR_SIZE?  Let's see if
			 * it's really necessary, first.
			 */
			if (tu->tu_size > TWE_SECTOR_SIZE) {
#ifdef TWE_DEBUG
				printf("%s: TWEIO_COMMAND: tu_size = %zu\n",
				    device_xname(twe->sc_dev), tu->tu_size);
#endif
				return EINVAL;
			}
			pdata = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_WAITOK);
			error = copyin(tu->tu_data, pdata, tu->tu_size);
			if (error != 0)
				goto done;
			ccb = twe_ccb_alloc_wait(twe,
			    TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
			KASSERT(ccb != NULL);
			ccb->ccb_data = pdata;
			ccb->ccb_datasize = TWE_SECTOR_SIZE;
		} else {
			ccb = twe_ccb_alloc_wait(twe, 0);
			KASSERT(ccb != NULL);
		}

		ccb->ccb_tx.tx_handler = twe_ccb_wait_handler;
		ccb->ccb_tx.tx_context = NULL;
		ccb->ccb_tx.tx_dv = twe->sc_dev;

		cmdid = ccb->ccb_cmdid;
		memcpy(ccb->ccb_cmd, &tu->tu_cmd, sizeof(struct twe_cmd));
		ccb->ccb_cmd->tc_cmdid = cmdid;

		/* Map the transfer. */
		if ((error = twe_ccb_map(twe, ccb)) != 0) {
			twe_ccb_free(twe, ccb);
			goto done;
		}

		/* Submit the command and wait up to 1 minute. */
		error = 0;
		twe_ccb_enqueue(twe, ccb);
		s = splbio();
		while ((ccb->ccb_flags & TWE_CCB_COMPLETE) == 0)
			if ((error = tsleep(ccb, PRIBIO, "tweioctl",
					    60 * hz)) != 0)
				break;
		splx(s);

		/* Copy the command back to the ioctl argument. */
		memcpy(&tu->tu_cmd, ccb->ccb_cmd, sizeof(struct twe_cmd));
#ifdef TWE_DEBUG
		printf("%s: TWEIO_COMMAND: tc_opcode = 0x%02x, "
		    "tc_status = 0x%02x\n", device_xname(twe->sc_dev),
		    tu->tu_cmd.tc_opcode, tu->tu_cmd.tc_status);
#endif

		s = splbio();
		twe_ccb_free(twe, ccb);
		splx(s);

		if (tu->tu_size > 0)
			error = copyout(pdata, tu->tu_data, tu->tu_size);
		goto done;

	case TWEIO_STATS:
		return (ENOENT);

	case TWEIO_AEN_POLL:
		s = splbio();
		*(u_int *)data = twe_aen_dequeue(twe);
		splx(s);
		return (0);

	case TWEIO_AEN_WAIT:
		s = splbio();
		while ((*(u_int *)data =
		    twe_aen_dequeue(twe)) == TWE_AEN_QUEUE_EMPTY) {
			twe->sc_flags |= TWEF_AENQ_WAIT;
			error = tsleep(&twe->sc_aen_queue, PRIBIO | PCATCH,
			    "tweaen", 0);
			if (error == EINTR) {
				splx(s);
				return (error);
			}
		}
		splx(s);
		return (0);

	case TWEIO_GET_PARAM:
		error = twe_param_get(twe, tp->tp_table_id, tp->tp_param_id,
		    tp->tp_size, 0, &param);
		if (error != 0)
			return (error);
		if (param->tp_param_size > tp->tp_size) {
			error = EFAULT;
			goto done;
		}
		error = copyout(param->tp_data, tp->tp_data,
		    param->tp_param_size);
		free(param, M_DEVBUF);
		goto done;

	case TWEIO_SET_PARAM:
		pdata = malloc(tp->tp_size, M_DEVBUF, M_WAITOK);
		if ((error = copyin(tp->tp_data, pdata, tp->tp_size)) != 0)
			goto done;
		error = twe_param_set(twe, tp->tp_table_id, tp->tp_param_id,
		    tp->tp_size, pdata);
		goto done;

	case TWEIO_RESET:
		s = splbio();
		twe_reset(twe);
		splx(s);
		return (0);

	case TWEIO_ADD_UNIT:
		/* XXX mutex */
		return (twe_add_unit(twe, td->td_unit));

	case TWEIO_DEL_UNIT:
		/* XXX mutex */
		return (twe_del_unit(twe, td->td_unit));

	default:
		return EINVAL;
	}
done:
	if (pdata)
		free(pdata, M_DEVBUF);
	return error;
}
Ejemplo n.º 2
0
int
tctrlioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
{
	struct tctrl_req req, *reqn;
	struct tctrl_pwr *pwrreq;
	struct apm_power_info *powerp;
	struct apm_event_info *evp;
	struct tctrl_softc *sc;
	int i;
	uint8_t c;

	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
	if (!sc)
		return ENXIO;

        switch (cmd) {

	case APM_IOC_STANDBY:
		/* turn off backlight and so on ? */
		
		return 0; /* for now */

	case APM_IOC_SUSPEND:
		/* not sure what to do here - we can't really suspend */
		
		return 0; /* for now */

	case OAPM_IOC_GETPOWER:
	case APM_IOC_GETPOWER:
		powerp = (struct apm_power_info *)data;
		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
		req.cmdlen = 1;
		req.rsplen = 2;
		tadpole_request(&req, 0, l->l_proc ? 1 : 0);
		if (req.rspbuf[0] > 0x00)
			powerp->battery_state = APM_BATT_CHARGING;
		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
		req.cmdlen = 1;
		req.rsplen = 3;
		tadpole_request(&req, 0, l->l_proc ? 1 : 0);
		c = req.rspbuf[0];
		powerp->battery_life = c;
		if (c > 0x70)	/* the tadpole sometimes dips below zero, and */
			c = 0;	/* into the 255 range. */
		powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
		if (powerp->battery_state != APM_BATT_CHARGING) {
			if (c < 0x20)
				powerp->battery_state = APM_BATT_CRITICAL;
			else if (c < 0x40)
				powerp->battery_state = APM_BATT_LOW;
			else if (c < 0x66)
				powerp->battery_state = APM_BATT_HIGH;
			else
				powerp->battery_state = APM_BATT_UNKNOWN;
		}
		
		if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
			powerp->ac_state = APM_AC_ON;
		else
			powerp->ac_state = APM_AC_OFF;
		break;

	case APM_IOC_NEXTEVENT:
		if (!sc->sc_event_count)
			return EAGAIN;

		evp = (struct apm_event_info *)data;
		i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
		i %= APM_NEVENTS;
		*evp = sc->sc_event_list[i];
		sc->sc_event_count--;
		return(0);

	/* this ioctl assumes the caller knows exactly what he is doing */
	case TCTRL_CMD_REQ:
		reqn = (struct tctrl_req *)data;
		if ((i = kauth_authorize_device_passthru(l->l_cred,
		    dev, KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data)) != 0 &&
		    (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
		    (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
		    reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
		    reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
		    reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
		    reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
		    (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
		    reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
		    reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
			return(i);
		tadpole_request(reqn, 0, l->l_proc ? 1 : 0);
		break;
	/* serial power mode (via auxiotwo) */
	case TCTRL_SERIAL_PWR:
		pwrreq = (struct tctrl_pwr *)data;
		if (pwrreq->rw)
			pwrreq->state = auxiotwoserialgetapm();
		else
			auxiotwoserialsetapm(pwrreq->state);
		break;

	/* modem power mode (via auxio) */
	case TCTRL_MODEM_PWR:
		return(EOPNOTSUPP); /* for now */
		break;


        default:
                return (ENOTTY);
        }
        return (0);
}