Example #1
0
status_t
SerialDevice::Open(uint32 flags)
{
	if (fDeviceOpen)
		return B_BUSY;

	if (fDeviceRemoved)
		return B_DEV_NOT_READY;

	gTTYModule->ttyinit(&fTTY, true);
	fTTYFile.tty = &fTTY;
	fTTYFile.flags = flags;
	ResetDevice();

	struct ddrover *ddr = gTTYModule->ddrstart(NULL);
	if (!ddr)
		return B_NO_MEMORY;

	gTTYModule->ddacquire(ddr, &gSerialDomain);
	status_t status = gTTYModule->ttyopen(&fTTYFile, ddr, usb_serial_service);
	gTTYModule->ddrdone(ddr);

	if (status < B_OK) {
		TRACE_ALWAYS("open: failed to open tty\n");
		return status;
	}

	fDeviceThread = spawn_kernel_thread(DeviceThread, "usb_serial device thread",
		B_NORMAL_PRIORITY, this);

	if (fDeviceThread < B_OK) {
		TRACE_ALWAYS("open: failed to spawn kernel thread\n");
		return fDeviceThread;
	}

	resume_thread(fDeviceThread);

	fControlOut = CLS_LINE_DTR | CLS_LINE_RTS;
	SetControlLineState(fControlOut);

	status = gUSBModule->queue_interrupt(fControlPipe, fInterruptBuffer,
		fInterruptBufferSize, InterruptCallbackFunction, this);
	if (status < B_OK)
		TRACE_ALWAYS("failed to queue initial interrupt\n");

	fDeviceOpen = true;
	return B_OK;
}
Example #2
0
//*****************************************************************************
//
// Handles CDC driver notifications related to control and setup of the device.
//
// \param pvCBData is the client-supplied callback pointer for this channel.
// \param ui32Event identifies the event we are being notified about.
// \param ui32MsgValue is an event-specific value.
// \param pvMsgData is an event-specific pointer.
//
// This function is called by the CDC driver to perform control-related
// operations on behalf of the USB host.  These functions include setting
// and querying the serial communication parameters, setting handshake line
// states and sending break conditions.
//
// \return The return value is event-specific.
//
//*****************************************************************************
uint32_t
ControlHandler(void *pvCBData, uint32_t ui32Event,
               uint32_t ui32MsgValue, void *pvMsgData)
{
    uint32_t ui32IntsOff;

    //
    // Which event are we being asked to process?
    //
    switch(ui32Event)
    {
        //
        // We are connected to a host and communication is now possible.
        //
        case USB_EVENT_CONNECTED:
            g_bUSBConfigured = true;

            //
            // Flush our buffers.
            //
            USBBufferFlush(&g_sTxBuffer);
            USBBufferFlush(&g_sRxBuffer);

            //
            // Tell the main loop to update the display.
            //
            ui32IntsOff = ROM_IntMasterDisable();
            g_pcStatus = "Connected";
            g_ui32Flags |= COMMAND_STATUS_UPDATE;
            if(!ui32IntsOff)
            {
                ROM_IntMasterEnable();
            }
            break;

        //
        // The host has disconnected.
        //
        case USB_EVENT_DISCONNECTED:
            g_bUSBConfigured = false;
            ui32IntsOff = ROM_IntMasterDisable();
            g_pcStatus = "Disconnected";
            g_ui32Flags |= COMMAND_STATUS_UPDATE;
            if(!ui32IntsOff)
            {
                ROM_IntMasterEnable();
            }
            break;

        //
        // Return the current serial communication parameters.
        //
        case USBD_CDC_EVENT_GET_LINE_CODING:
            GetLineCoding(pvMsgData);
            break;

        //
        // Set the current serial communication parameters.
        //
        case USBD_CDC_EVENT_SET_LINE_CODING:
            SetLineCoding(pvMsgData);
            break;

        //
        // Set the current serial communication parameters.
        //
        case USBD_CDC_EVENT_SET_CONTROL_LINE_STATE:
            SetControlLineState((uint16_t)ui32MsgValue);
            break;

        //
        // Send a break condition on the serial line.
        //
        case USBD_CDC_EVENT_SEND_BREAK:
            SendBreak(true);
            break;

        //
        // Clear the break condition on the serial line.
        //
        case USBD_CDC_EVENT_CLEAR_BREAK:
            SendBreak(false);
            break;

        //
        // Ignore SUSPEND and RESUME for now.
        //
        case USB_EVENT_SUSPEND:
        case USB_EVENT_RESUME:
            break;

        //
        // We don't expect to receive any other events.  Ignore any that show
        // up in a release build or hang in a debug build.
        //
        default:
#ifdef DEBUG
            while(1);
#else
            break;
#endif

    }

    return(0);
}
//*****************************************************************************
//
// Handles CDC driver notifications related to control and setup of the device.
//
// \param pvCBData is the client-supplied callback pointer for this channel.
// \param ulEvent identifies the event we are being notified about.
// \param ulMsgValue is an event-specific value.
// \param pvMsgData is an event-specific pointer.
//
// This function is called by the CDC driver to perform control-related
// operations on behalf of the USB host.  These functions include setting
// and querying the serial communication parameters, setting handshake line
// states and sending break conditions.
//
// \return The return value is event-specific.
//
//*****************************************************************************
uint32_t
ControlHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
               void *pvMsgData)
{
    //
    // Which event are we being asked to process?
    //
    switch(ui32Event)
    {
        //
        // We are connected to a host and communication is now possible.
        //
        case USB_EVENT_CONNECTED:
        {
            //
            // Now connected and ready for normal operation.
            //
            HWREGBITW(&g_ui32Flags, FLAG_USB_CONFIGURED) = 1;

            //
            // Flush our buffers.
            //
            USBBufferFlush(&g_sTxBuffer);
            USBBufferFlush(&g_sRxBuffer);

            //
            // Tell the main loop to update the display.
            //
            g_pcStatus = "Host connected.";

            //
            // Set the command status update flag.
            //
            HWREGBITW(&g_ui32Flags, FLAG_STATUS_UPDATE) = 1;

            break;
        }

        //
        // The host has disconnected.
        //
        case USB_EVENT_DISCONNECTED:
        {
            //
            // No longer connected.
            //
            HWREGBITW(&g_ui32Flags, FLAG_USB_CONFIGURED) = 0;

            g_pcStatus = "Host disconnected.";

            //
            // Set the command status update flag.
            //
            HWREGBITW(&g_ui32Flags, FLAG_STATUS_UPDATE) = 1;

            break;
        }

        //
        // Return the current serial communication parameters.
        //
        case USBD_CDC_EVENT_GET_LINE_CODING:
        {
            GetLineCoding(pvMsgData, UART_CLOCK);
            break;
        }

        //
        // Set the current serial communication parameters.
        //
        case USBD_CDC_EVENT_SET_LINE_CODING:
        {
            SetLineCoding(pvMsgData, UART_CLOCK);
            break;
        }

        //
        // Set the current serial communication parameters.
        //
        case USBD_CDC_EVENT_SET_CONTROL_LINE_STATE:
        {
            SetControlLineState((uint16_t)ui32MsgValue);
            break;
        }

        //
        // Send a break condition on the serial line.
        //
        case USBD_CDC_EVENT_SEND_BREAK:
        {
            SendBreak(true);
            break;
        }

        //
        // Clear the break condition on the serial line.
        //
        case USBD_CDC_EVENT_CLEAR_BREAK:
        {
            SendBreak(false);
            break;
        }

        //
        // Ignore SUSPEND and RESUME for now.
        //
        case USB_EVENT_SUSPEND:
        case USB_EVENT_RESUME:
        {
            break;
        }

        //
        // We don't expect to receive any other events.  Ignore any that show
        // up in a release build or hang in a debug build.
        //
        default:
        {
#ifdef DEBUG
            while(1);
#else
            break;
#endif
        }

    }

    return(0);
}
Example #4
0
bool
SerialDevice::Service(struct tty *ptty, struct ddrover *ddr, uint flags)
{
	if (&fTTY != ptty)
		return false;

	if (flags <= TTYGETSIGNALS) {
		switch (flags) {
			case TTYENABLE:
				TRACE("TTYENABLE\n");
				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false);
				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
				fControlOut = CLS_LINE_DTR | CLS_LINE_RTS;
				SetControlLineState(fControlOut);
				break;

			case TTYDISABLE:
				TRACE("TTYDISABLE\n");
				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false);
				fControlOut = 0x0;
				SetControlLineState(fControlOut);
				break;

			case TTYISTOP:
				TRACE("TTYISTOP\n");
				fInputStopped = true;
				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false);
				break;

			case TTYIRESUME:
				TRACE("TTYIRESUME\n");
				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
				fInputStopped = false;
				break;

			case TTYGETSIGNALS:
				TRACE("TTYGETSIGNALS\n");
				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, true);
				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDSR, false);
				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWRI, false);
				break;

			case TTYSETMODES:
				TRACE("TTYSETMODES\n");
				SetModes();
				break;

			case TTYOSTART:
			case TTYOSYNC:
			case TTYSETBREAK:
			case TTYCLRBREAK:
			case TTYSETDTR:
			case TTYCLRDTR:
				TRACE("TTY other\n");
				break;
		}

		return true;
	}

	return false;
}
Example #5
0
void
SerialDevice::SetModes()
{
	struct termios tios;
	memcpy(&tios, &fTTY.t, sizeof(struct termios));
	uint16 newControl = fControlOut;
	TRACE_FUNCRES(trace_termios, &tios);

	static uint32 baudRates[] = {
		0x00000000, //B0
		0x00000032, //B50
		0x0000004B, //B75
		0x0000006E, //B110
		0x00000086, //B134
		0x00000096, //B150
		0x000000C8, //B200
		0x0000012C, //B300
		0x00000258, //B600
		0x000004B0, //B1200
		0x00000708, //B1800
		0x00000960, //B2400
		0x000012C0, //B4800
		0x00002580, //B9600
		0x00004B00, //B19200
		0x00009600, //B38400
		0x0000E100, //B57600
		0x0001C200, //B115200
		0x00038400, //B230400
		0x00070800, //460800
		0x000E1000, //921600
	};

	uint32 baudCount = sizeof(baudRates) / sizeof(baudRates[0]);
	uint32 baudIndex = tios.c_cflag & CBAUD;
	if (baudIndex > baudCount)
		baudIndex = baudCount - 1;

	usb_serial_line_coding lineCoding;
	lineCoding.speed = baudRates[baudIndex];
	lineCoding.stopbits = (tios.c_cflag & CSTOPB) ? LC_STOP_BIT_2 : LC_STOP_BIT_1;

	if (tios.c_cflag & PARENB) {
		lineCoding.parity = LC_PARITY_EVEN;
		if (tios.c_cflag & PARODD)
			lineCoding.parity = LC_PARITY_ODD;
	} else
		lineCoding.parity = LC_PARITY_NONE;

	lineCoding.databits = (tios.c_cflag & CS8) ? 8 : 7;

	if (lineCoding.speed == 0) {
		newControl &= 0xfffffffe;
		lineCoding.speed = fLineCoding.speed;
	} else
		newControl = CLS_LINE_DTR;

	if (fControlOut != newControl) {
		fControlOut = newControl;
		TRACE("newctrl send to modem: 0x%08x\n", newControl);
		SetControlLineState(newControl);
	}

	if (memcmp(&lineCoding, &fLineCoding, sizeof(usb_serial_line_coding)) != 0) {
		fLineCoding.speed = lineCoding.speed;
		fLineCoding.stopbits = lineCoding.stopbits;
		fLineCoding.databits = lineCoding.databits;
		fLineCoding.parity = lineCoding.parity;
		TRACE("send to modem: speed %d sb: 0x%08x db: 0x%08x parity: 0x%08x\n",
			fLineCoding.speed, fLineCoding.stopbits, fLineCoding.databits,
			fLineCoding.parity);
		SetLineCoding(&fLineCoding);
	}
}
Example #6
0
status_t
SerialDevice::Open(uint32 flags)
{
	if (fDeviceOpen)
		return B_BUSY;

	if (fDeviceRemoved)
		return B_DEV_NOT_READY;

	fMasterTTY = gTTYModule->tty_create(usb_serial_service, true);
	if (fMasterTTY == NULL) {
		TRACE_ALWAYS("open: failed to init master tty\n");
		return B_NO_MEMORY;
	}

	fSlaveTTY = gTTYModule->tty_create(usb_serial_service, false);
	if (fSlaveTTY == NULL) {
		TRACE_ALWAYS("open: failed to init slave tty\n");
		gTTYModule->tty_destroy(fMasterTTY);
		return B_NO_MEMORY;
	}

	fSystemTTYCookie = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY,
		O_RDWR);
	if (fSystemTTYCookie == NULL) {
		TRACE_ALWAYS("open: failed to init system tty cookie\n");
		gTTYModule->tty_destroy(fMasterTTY);
		gTTYModule->tty_destroy(fSlaveTTY);
		return B_NO_MEMORY;
	}

	fDeviceTTYCookie = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY,
		O_RDWR);
	if (fDeviceTTYCookie == NULL) {
		TRACE_ALWAYS("open: failed to init device tty cookie\n");
		gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
		gTTYModule->tty_destroy(fMasterTTY);
		gTTYModule->tty_destroy(fSlaveTTY);
		return B_NO_MEMORY;
	}

	ResetDevice();

	fStopThreads = false;

	fInputThread = spawn_kernel_thread(_InputThread,
		"usb_serial input thread", B_NORMAL_PRIORITY, this);
	if (fInputThread < 0) {
		TRACE_ALWAYS("open: failed to spawn input thread\n");
		return fInputThread;
	}

	resume_thread(fInputThread);

	fControlOut = USB_CDC_CONTROL_SIGNAL_STATE_DTR
		| USB_CDC_CONTROL_SIGNAL_STATE_RTS;
	SetControlLineState(fControlOut);

	status_t status = gUSBModule->queue_interrupt(fControlPipe,
		fInterruptBuffer, fInterruptBufferSize, _InterruptCallbackFunction,
		this);
	if (status < B_OK)
		TRACE_ALWAYS("failed to queue initial interrupt\n");

	// set our config (will propagate to the slave config as well in SetModes()
	gTTYModule->tty_control(fSystemTTYCookie, TCSETA, &fTTYConfig,
		sizeof(termios));

	fDeviceOpen = true;
	return B_OK;
}
Example #7
0
bool
SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length)
{
	if (tty != fMasterTTY)
		return false;

	switch (op) {
		case TTYENABLE:
		{
			bool enable = *(bool *)buffer;
			TRACE("TTYENABLE: %sable\n", enable ? "en" : "dis");

			gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDCD, enable);
			gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, enable);

			fControlOut = enable ? USB_CDC_CONTROL_SIGNAL_STATE_DTR
				| USB_CDC_CONTROL_SIGNAL_STATE_RTS : 0;
			SetControlLineState(fControlOut);
			return true;
		}

		case TTYISTOP:
			fInputStopped = *(bool *)buffer;
			TRACE("TTYISTOP: %sstopped\n", fInputStopped ? "" : "not ");
			gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS,
				!fInputStopped);
			return true;

		case TTYGETSIGNALS:
			TRACE("TTYGETSIGNALS\n");
			gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDCD,
				(fControlOut & (USB_CDC_CONTROL_SIGNAL_STATE_DTR
					| USB_CDC_CONTROL_SIGNAL_STATE_RTS)) != 0);
			gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS,
				!fInputStopped);
			gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDSR, false);
			gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWRI, false);
			return true;

		case TTYSETMODES:
			TRACE("TTYSETMODES\n");
			SetModes((struct termios *)buffer);
			return true;

		case TTYSETDTR:
		case TTYSETRTS:
		{
			bool set = *(bool *)buffer;
			uint8 bit = op == TTYSETDTR ? USB_CDC_CONTROL_SIGNAL_STATE_DTR
				: USB_CDC_CONTROL_SIGNAL_STATE_RTS;
			if (set)
				fControlOut |= bit;
			else
				fControlOut &= ~bit;

			SetControlLineState(fControlOut);
			return true;
		}

		case TTYOSTART:
		case TTYOSYNC:
		case TTYSETBREAK:
			TRACE("TTY other\n");
			return true;
	}

	return false;
}
Example #8
0
/******************************************************************************
*																			  *
* \brief  Handles CDC driver notifications related to control and setup of    *
*         the device.\n                                                       *
*                                                                             *
* \param pvCBData is the client-supplied callback pointer for this channel.   *
*																		      *
* \param ulEvent identifies the event we are being notified about.            *
*																		      *
* \param ulMsgValue is an event-specific value.                               *
*																		      *
* \param pvMsgData is an event-specific pointer.                              *
*																		      *
* \return The return value is event-specific.                                 *
*                                                                             *
******************************************************************************/
unsigned int ControlHandler(void *pvCBData, unsigned int ulEvent,
                            unsigned int ulMsgValue, void *pvMsgData)
{
    unsigned char ulIntsOff;

    
    /* Which event are we being asked to process? */
    
    switch(ulEvent)
    {
        
        /* We are connected to a host and communication is now possible. */
        
        case USB_EVENT_CONNECTED:
            
            /* Flush our buffers. */
            
            USBBufferFlush(&g_sTxBuffer);
            USBBufferFlush(&g_sRxBuffer);
            ulIntsOff = IntDisable();
            g_pcStatus = "Host connected.";
            g_ulFlags |= COMMAND_STATUS_UPDATE;
			IntEnable(ulIntsOff);
            break;

        
        /* The host has disconnected. */
        
        case USB_EVENT_DISCONNECTED:

            ulIntsOff = IntDisable();
            g_pcStatus = "Host disconnected.";
            g_ulFlags |= COMMAND_STATUS_UPDATE;
         	IntEnable(ulIntsOff);
            break;

        
        /* Return the current serial communication parameters. */
        
        case USBD_CDC_EVENT_GET_LINE_CODING:
            GetLineCoding(pvMsgData);
            break;

        
        /* Set the current serial communication parameters. */
        
        case USBD_CDC_EVENT_SET_LINE_CODING:
            SetLineCoding(pvMsgData);
            break;

        /* Set the current serial communication parameters. */
        
        case USBD_CDC_EVENT_SET_CONTROL_LINE_STATE:
            SetControlLineState((unsigned short)ulMsgValue);
            break;
        
        /* Send a break condition on the serial line.*/
        
        case USBD_CDC_EVENT_SEND_BREAK:
            SendBreak(true);
            break;
        
        /* Clear the break condition on the serial line. */
        
        case USBD_CDC_EVENT_CLEAR_BREAK:
            SendBreak(false);
            break;
       
        /* Ignore SUSPEND and RESUME for now. */
        
        case USB_EVENT_SUSPEND:
        case USB_EVENT_RESUME:
            break;

        /* We don't expect to receive any other events.  Ignore any that show
           up in a release build or hang in a debug build.
        */
        default:
            break;
    }

    return(0);
}