A library to send and receive MIDI messages over USB using the default USB-MIDI drivers on Win/Mac
Fork of USBMIDI by
usbcore.c
- Committer:
- simon
- Date:
- 2011-02-20
- Revision:
- 2:10d694d6ccdc
- Parent:
- 1:ff74eabe02cd
File content as of revision 2:10d694d6ccdc:
/* @license The MIT License * Copyright (c) 2011 mux, simon * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "usbcore.h" #include "mbed.h" // Serial Interface Engine #define SIE_SET_ADDR (0xD0) #define SIE_SET_STATUS (0xFE) #define SIE_GET_STATUS (0xFE) #define SIE_SET_MODE (0xF3) #define SIE_CLR_BUFFER (0xF2) #define SIE_VAL_BUFFER (0xFA) #define SIE_SEL_EP (0x00) #define SIE_SEL_CLR_EP (0x28) #define SIE_SET_EP_STAT (0x40) #define SIE_READ_ERROR (0xFB) #define SIE_CONFIG_DEVICE (0xD8) // EP status #define EP_FE (1<<0) // Full/Empty #define EP_ST (1<<1) // Stalled endpoint #define EP_STP (1<<2) // Setup packet #define EP_PO (1<<3) // packet overwritten #define EP_EPN (1<<4) // EP NAKed #define B_1_FULL (1<<5) // buffer 1 status #define B_2_FULL (1<<6) // buffer 2 status // USB device interrupts #define DEV_FRAME (1<<0) #define EP_FAST (1<<1) #define EP_SLOW (1<<2) #define DEV_STAT (1<<3) #define RxENDPKT (1<<6) #define TxENDPKT (1<<7) #define EP_RLZED (1<<8) #define CCEMPTY (0x10) #define CDFULL (0x20) // USB device status bits #define STAT_CON (1<<0) #define STAT_CON_CH (1<<1) #define STAT_SUS (1<<2) #define STAT_SUS_CH (1<<3) #define STAT_RST (1<<4) // end points interrupts #define EP0RX_INT (1<<0) #define EP0TX_INT (1<<1) #define EP1RX_INT (1<<2) #define EP1TX_INT (1<<3) #define EP2RX_INT (1<<4) #define EP2TX_INT (1<<5) // USB control register #define RD_EN (1<<0) #define WR_EN (1<<1) #define PKT_RDY (1<<11) #define LOG_ENDPOINT(ep) ((ep>>1)<<2) // configure state static int configured = 0; // USB interrupt handler void USB_IRQHandler(void); // Serial Interface Engine functions void sie_command(uint32_t code) { LPC_USB->USBDevIntClr = CCEMPTY; // clear CCEMPTY LPC_USB->USBCmdCode = ((code<<16)|(0x05<<8)); // CMD_PHASE=Command while (!(LPC_USB->USBDevIntSt & CCEMPTY)); // wait for CCEMPTY } void sie_write(uint32_t data) { LPC_USB->USBDevIntClr = CCEMPTY; // clear CCEMPTY LPC_USB->USBCmdCode = ((data<<16)|(0x01<<8)); // CMD_PHASE=Write while (!(LPC_USB->USBDevIntSt & CCEMPTY)); // wait for CCEMPTY } uint8_t sie_read(uint32_t code) { LPC_USB->USBDevIntClr = CDFULL; // clear CCEMPTY LPC_USB->USBCmdCode = ((code<<16)|(0x02<<8)); // CMD_PHASE=Read while (!(LPC_USB->USBDevIntSt & CDFULL)); // wait for CDFULL return (uint8_t) LPC_USB->USBCmdData; } // end point functions void ep_realize(uint8_t ep, uint32_t size) { LPC_USB->USBDevIntClr = EP_RLZED; // clear EP_RLZED LPC_USB->USBReEp |= (1<<ep); LPC_USB->USBEpInd = ep; // set USBEpIn LPC_USB->USBMaxPSize = size; // writing to EPn pointed to by USBEpInd while (!(LPC_USB->USBDevIntSt & EP_RLZED)); // wait for EP_RLZED LPC_USB->USBDevIntClr = EP_RLZED; // clear EP_RLZED } void ep_stall(uint8_t ep) { sie_command(SIE_SET_EP_STAT+ep); sie_write(1); } void ep_unstall(uint8_t ep) { sie_command(SIE_SET_EP_STAT+ep); sie_write(0); } // initializes a pointer to the endpoint buffer uint8_t ep_select(uint8_t ep) { sie_command(SIE_SEL_EP+ep); return sie_read(SIE_SEL_EP+ep); } uint8_t ep_select_clear(uint8_t ep) { LPC_USB->USBEpIntClr |= ep; // clear ep interrupt while (!(LPC_USB->USBDevIntSt & CDFULL)); // wait for cmd finish return LPC_USB->USBCmdData; } int ep_readable(uint8_t ep) { uint8_t st = ep_select(ep); return (st & EP_FE); } int ep_writable(uint8_t ep) { uint8_t st = ep_select(ep); return !(st & EP_FE); } int ep_read(uint8_t ep, uint8_t *tbuf) { uint32_t *buf = (uint32_t*) tbuf; LPC_USB->USBCtrl = LOG_ENDPOINT(ep)|RD_EN; // RD_EN bit and LOG_ENDPOINT while (!(LPC_USB->USBRxPLen & PKT_RDY)); // wait for packet to be fetched int len = LPC_USB->USBRxPLen & 0x3FF; // read and mask packet length while (!(LPC_USB->USBDevIntSt & RxENDPKT)) { *buf++ = LPC_USB->USBRxData; } LPC_USB->USBCtrl = 0; LPC_USB->USBDevIntClr |= RxENDPKT; sie_command(SIE_SEL_EP+ep); // select endpoint sie_command(SIE_CLR_BUFFER); // clear RX buffer return len; } void ep_write(uint8_t ep, uint8_t *tbuf, uint32_t len) { uint32_t *buf = (uint32_t*) tbuf; LPC_USB->USBCtrl = LOG_ENDPOINT(ep)|WR_EN; // RD_EN bit and LOG_ENDPOINT LPC_USB->USBTxPLen |= (len & 0x3FF); // write and mask packet length while (!(LPC_USB->USBDevIntSt & TxENDPKT)) { LPC_USB->USBTxData = *buf++; } LPC_USB->USBCtrl = 0; LPC_USB->USBDevIntClr |= TxENDPKT; sie_command(SIE_SEL_EP+ep); // select endpoint sie_command(SIE_VAL_BUFFER); // validate TX buffer } // USB device controller initialization void usb_init() { // USB D+/D- pinsel functions LPC_PINCON->PINSEL1 &= 0xC3FFFFFF; LPC_PINCON->PINSEL1 |= 0x14000000; #if USB_UP_DEBUG // USB_UP_LED pinsel function LPC_PINCON->PINSEL3 &= 0xFFFFFFCF; LPC_PINCON->PINSEL3 |= 0x00000010; #endif // USB connect pinsel function LPC_PINCON->PINSEL4 &= 0xFFFCFFFF; LPC_PINCON->PINSEL4 |= 0x00040000; LPC_SC->PCONP |= (1UL<<31); // enable the USB controller LPC_USB->USBClkCtrl |= ((1<<1)|(1<<4)); // enable the AHB and DEV clocks while ((LPC_USB->USBClkSt & 0x12) != 0x12); // wait for the clocks to init NVIC_SetVector(USB_IRQn, (uint32_t)&USB_IRQHandler); NVIC_EnableIRQ(USB_IRQn); // enable USB interrupts usb_reset(); usb_set_address(0); // default address } void usb_reset() { ep_realize(EP0, MAX_EP0_PSIZE); ep_realize(EP1, MAX_EP0_PSIZE); LPC_USB->USBEpIntClr = 0xFFFFFFFF; // clear end points interrupts LPC_USB->USBEpIntEn = 0xFFFFFFFF; // enable end points interrupts LPC_USB->USBEpIntPri = 0x0; // route to EP_SLOW LPC_USB->USBDevIntClr = 0xFFFFFFFF; // clear USB device interrupts LPC_USB->USBDevIntEn = (EP_SLOW|DEV_STAT); // enable USB device interrupts } void usb_configure(uint8_t conf) { sie_command(SIE_CONFIG_DEVICE); sie_write(conf); configured = 1; } int usb_configured() { return configured; } void usb_set_address(uint8_t addr) { sie_command(SIE_SET_ADDR); sie_write(addr|0x80); // DEV_EN = 1 } uint8_t usb_get_status() { sie_command(SIE_GET_STATUS); return sie_read(SIE_GET_STATUS); } void usb_connect() { sie_command(SIE_GET_STATUS); // read current status uint8_t st = sie_read(SIE_GET_STATUS); sie_command(SIE_SET_STATUS); // set STAT_CON bit sie_write(st|STAT_CON); } void USB_IRQHandler(void) { if (LPC_USB->USBDevIntSt & DEV_STAT) { // DEV_STAT interrupt LPC_USB->USBDevIntClr |= DEV_STAT; if (usb_get_status() & STAT_RST) { // bus reset usb_reset(); } return; } if (LPC_USB->USBDevIntSt & EP_SLOW) { // EP_SLOW interrupt if (LPC_USB->USBEpIntSt & EP0RX_INT) { if (ep_select_clear(EP0RX_INT) & EP_STP) { // setup transfer ep0_setup(); } else { ep0_out(); } } if (LPC_USB->USBEpIntSt & EP0TX_INT) { ep_select_clear(EP0TX_INT); ep0_in(); } if (LPC_USB->USBEpIntSt & EP2RX_INT) { ep_select_clear(EP2TX_INT); ep2_out(); } if (LPC_USB->USBEpIntSt & EP2TX_INT) { ep_select_clear(EP2TX_INT); ep2_in(); } // EP_SLOW should be cleared after clearing EPs interrupts LPC_USB->USBDevIntClr |= EP_SLOW; } }