FreeBSD/sys/dev/usb/wlan/if_uath.c
/*
 * Low-level function to send read or write commands to the firmware.
 */
Low-level function to send read or write commands to the firmware.
Low - level function to send read or write commands to the firmware .
static int
uath_cmdsend(struct uath_softc *sc, uint32_t code, const void *idata, int ilen,
    void *odata, int olen, int flags)
{
	struct uath_cmd_hdr *hdr;
	struct uath_cmd *cmd;
	int error;
	UATH_ASSERT_LOCKED(sc);
	cmd = uath_get_cmdbuf(sc);
	if (cmd == NULL) {
		device_printf(sc->sc_dev, "%s: empty inactive queue\n",
		    __func__);
		return (ENOBUFS);
	}
	cmd->flags = flags;
	cmd->buflen = roundup2(sizeof(struct uath_cmd_hdr) + ilen, 4);
	hdr = (struct uath_cmd_hdr *)cmd->buf;
	memset(hdr, 0, sizeof(struct uath_cmd_hdr));
	hdr->len   = htobe32(cmd->buflen);
	hdr->code  = htobe32(code);
	hdr->msgid = cmd->msgid;	
	hdr->magic = htobe32((cmd->flags & UATH_CMD_FLAG_MAGIC) ? 1 << 24 : 0);
	memcpy((uint8_t *)(hdr + 1), idata, ilen);
#ifdef UATH_DEBUG
	if (sc->sc_debug & UATH_DEBUG_CMDS) {
		printf("%s: send  %s [flags 0x%x] olen %d\n",
		    __func__, uath_codename(code), cmd->flags, olen);
		if (sc->sc_debug & UATH_DEBUG_CMDS_DUMP)
			uath_dump_cmd(cmd->buf, cmd->buflen, '+');
	}
#endif
	cmd->odata = odata;
	KASSERT(odata == NULL ||
	    olen < UATH_MAX_CMDSZ - sizeof(*hdr) + sizeof(uint32_t),
	    ("odata %p olen %u", odata, olen));
	cmd->olen = olen;
	STAILQ_INSERT_TAIL(&sc->sc_cmd_pending, cmd, next);
	UATH_STAT_INC(sc, st_cmd_pending);
	usbd_transfer_start(sc->sc_xfer[UATH_INTR_TX]);
	if (cmd->flags & UATH_CMD_FLAG_READ) {
		usbd_transfer_start(sc->sc_xfer[UATH_INTR_RX]);
		error = mtx_sleep(cmd, &sc->sc_mtx, 0, "uathcmd", 2 * hz);
		cmd->odata = NULL;	
		if (error != 0) {
			device_printf(sc->sc_dev, "timeout waiting for reply "
			    "to cmd 0x%x (%u)\n", code, code);
		} else if (cmd->olen != olen) {
			device_printf(sc->sc_dev, "unexpected reply data count "
			    "to cmd 0x%x (%u), got %u, expected %u\n",
			    code, code, cmd->olen, olen);
			error = EINVAL;
		}
		return (error);
	}
	return (0);
}
static int uath_cmdsend ( struct uath_softc * sc , uint32_t code , const void * idata , int ilen , void * odata , int olen , int flags ) { struct uath_cmd_hdr * hdr ; struct uath_cmd * cmd ; int error ; UATH_ASSERT_LOCKED ( sc ) ; cmd = uath_get_cmdbuf ( sc ) ; if ( cmd == NULL ) { device_printf ( sc -> sc_dev , " \n " , __func__ ) ; return ( ENOBUFS ) ; } cmd -> flags = flags ; cmd -> buflen = roundup2 ( sizeof ( struct uath_cmd_hdr ) + ilen , 4 ) ; hdr = ( struct uath_cmd_hdr * ) cmd -> buf ; memset ( hdr , 0 , sizeof ( struct uath_cmd_hdr ) ) ; hdr -> len = htobe32 ( cmd -> buflen ) ; hdr -> code = htobe32 ( code ) ; hdr -> msgid = cmd -> msgid ; hdr -> magic = htobe32 ( ( cmd -> flags & UATH_CMD_FLAG_MAGIC ) ? 1 << 24 : 0 ) ; memcpy ( ( uint8_t * ) ( hdr + 1 ) , idata , ilen ) ; #ifdef UATH_DEBUG if ( sc -> sc_debug & UATH_DEBUG_CMDS ) { printf ( " \n " , __func__ , uath_codename ( code ) , cmd -> flags , olen ) ; if ( sc -> sc_debug & UATH_DEBUG_CMDS_DUMP ) uath_dump_cmd ( cmd -> buf , cmd -> buflen , ' ' ) ; } #endif cmd -> odata = odata ; KASSERT ( odata == NULL || olen < UATH_MAX_CMDSZ - sizeof ( * hdr ) + sizeof ( uint32_t ) , ( " " , odata , olen ) ) ; cmd -> olen = olen ; STAILQ_INSERT_TAIL ( & sc -> sc_cmd_pending , cmd , next ) ; UATH_STAT_INC ( sc , st_cmd_pending ) ; usbd_transfer_start ( sc -> sc_xfer [ UATH_INTR_TX ] ) ; if ( cmd -> flags & UATH_CMD_FLAG_READ ) { usbd_transfer_start ( sc -> sc_xfer [ UATH_INTR_RX ] ) ; error = mtx_sleep ( cmd , & sc -> sc_mtx , 0 , " " , 2 * hz ) ; cmd -> odata = NULL ; if ( error != 0 ) { device_printf ( sc -> sc_dev , " " " \n " , code , code ) ; } else if ( cmd -> olen != olen ) { device_printf ( sc -> sc_dev , " " " \n " , code , code , cmd -> olen , olen ) ; error = EINVAL ; } return ( error ) ; } return ( 0 ) ; }
Low-level function to send read or write commands to the firmware.
Low - level function to send read or write commands to the firmware .
/* grab a xfer */ /* always bulk-out a multiple of 4 bytes */ /* don't care about endianness */ /* wait at most two seconds for command reply */ /* in case reply comes too late */