forked from Imagelibrary/rtems
bsps: Move libchip to bsps
This patch is a part of the BSP source reorganization. Update #3285.
This commit is contained in:
55
bsps/shared/dev/display/disp_fonts.h
Normal file
55
bsps/shared/dev/display/disp_fonts.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*===============================================================*\
|
||||
| Project: display driver for HCMS29xx |
|
||||
+-----------------------------------------------------------------+
|
||||
| File: disp_fonts.h |
|
||||
+-----------------------------------------------------------------+
|
||||
| Copyright (c) 2008 |
|
||||
| Embedded Brains GmbH |
|
||||
| Obere Lagerstr. 30 |
|
||||
| D-82178 Puchheim |
|
||||
| Germany |
|
||||
| rtems@embedded-brains.de |
|
||||
+-----------------------------------------------------------------+
|
||||
| The license and distribution terms for this file may be |
|
||||
| found in the file LICENSE in this distribution or at |
|
||||
| http://www.rtems.org/license/LICENSE. |
|
||||
| |
|
||||
+-----------------------------------------------------------------+
|
||||
| This file declares general data structures for font management |
|
||||
\*===============================================================*/
|
||||
|
||||
#ifndef DISP_FONTS_H
|
||||
#define DISP_FONTS_H
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
typedef int8_t disp_font_dimen;
|
||||
|
||||
struct disp_font_bounding_box
|
||||
{
|
||||
disp_font_dimen w, h, x, y;
|
||||
};
|
||||
|
||||
struct disp_font_glyph
|
||||
{
|
||||
struct disp_font_bounding_box bb;
|
||||
disp_font_dimen wx, wy;
|
||||
const unsigned char *bitmap;
|
||||
};
|
||||
|
||||
struct disp_font_base
|
||||
{
|
||||
int8_t trans;
|
||||
struct disp_font_bounding_box fbb;
|
||||
disp_font_dimen ascent, descent;
|
||||
uint8_t default_char;
|
||||
struct disp_font_glyph *latin1[256];
|
||||
};
|
||||
|
||||
typedef struct disp_font_base *disp_font_t;
|
||||
|
||||
/* Prototypes ------------------------------------------------- */
|
||||
|
||||
/* End -------------------------------------------------------- */
|
||||
|
||||
#endif /* not defined DISP_FONTS_H */
|
||||
932
bsps/shared/dev/display/disp_hcms29xx.c
Normal file
932
bsps/shared/dev/display/disp_hcms29xx.c
Normal file
@@ -0,0 +1,932 @@
|
||||
/*===============================================================*\
|
||||
| Project: display driver for HCMS29xx |
|
||||
+-----------------------------------------------------------------+
|
||||
| File: disp_hcms29xx.c |
|
||||
+-----------------------------------------------------------------+
|
||||
| Copyright (c) 2008 |
|
||||
| Embedded Brains GmbH |
|
||||
| Obere Lagerstr. 30 |
|
||||
| D-82178 Puchheim |
|
||||
| Germany |
|
||||
| rtems@embedded-brains.de |
|
||||
+-----------------------------------------------------------------+
|
||||
| The license and distribution terms for this file may be |
|
||||
| found in the file LICENSE in this distribution or at |
|
||||
| http://www.rtems.org/license/LICENSE. |
|
||||
+-----------------------------------------------------------------+
|
||||
| this file contains the SPI based driver for a HCMS29xx 4 digit |
|
||||
| alphanumeric LED display |
|
||||
\*===============================================================*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <bsp.h>
|
||||
#include <rtems/libi2c.h>
|
||||
#include <libchip/disp_hcms29xx.h>
|
||||
#include "font_hcms29xx.h"
|
||||
#define FONT_BASE font_hcms29xx_base
|
||||
|
||||
|
||||
#define DISP_HCMS29XX_DIGIT_CNT (4)
|
||||
#define DISP_HCMS29XX_SEMA_NAME rtems_build_name('D','4','I','Q')
|
||||
#define DISP_HCMS29XX_TRNS_SEMA_NAME rtems_build_name('D','4','T','R')
|
||||
#define DISP_HCMS29XX_TIMER_NAME rtems_build_name('D','4','T','M')
|
||||
#define DISP_HCMS29XX_TASK_NAME rtems_build_name('D','4','T','A')
|
||||
|
||||
#define DISP_HCMS29XX_EVENT_TIMER RTEMS_EVENT_1
|
||||
#define DISP_HCMS29XX_EVENT_NEWSTR RTEMS_EVENT_2
|
||||
|
||||
|
||||
static disp_font_t disp_hcms29xx_font_normal;
|
||||
static disp_font_t disp_hcms29xx_font_rotate;
|
||||
const rtems_libi2c_tfr_mode_t spi_disphcms29xx_tfr_mode = {
|
||||
.baudrate = 1000000,
|
||||
.bits_per_char = 8,
|
||||
.lsb_first = true,
|
||||
.clock_inv = true,
|
||||
.clock_phs = true,
|
||||
.idle_char = 0
|
||||
};
|
||||
|
||||
static disp_hcms29xx_drv_t disp_hcms29xx_drv_tbl;
|
||||
|
||||
/*=========================================
|
||||
* font management functions
|
||||
*/
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_status_code disp_hcms29xx_font_struct_size
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| compute size of font data structure tree |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
disp_font_t src, /* source font */
|
||||
size_t *dst_size /* destination: size of font struct*/
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
size_t font_size = 0;
|
||||
size_t glyph_idx;
|
||||
/*
|
||||
* check parameters
|
||||
*/
|
||||
if ((rc == RTEMS_SUCCESSFUL) &&
|
||||
(src == NULL)) {
|
||||
rc = RTEMS_INVALID_ADDRESS;
|
||||
}
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
font_size =
|
||||
sizeof(*src); /* font_base structure */
|
||||
}
|
||||
glyph_idx = 0;
|
||||
while ((rc == RTEMS_SUCCESSFUL) &&
|
||||
(glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0])))) {
|
||||
if (src->latin1[glyph_idx] != NULL) {
|
||||
font_size += sizeof(*(src->latin1[glyph_idx]))
|
||||
+ (size_t) src->latin1[glyph_idx]->bb.w;
|
||||
}
|
||||
glyph_idx++;
|
||||
}
|
||||
*dst_size = font_size;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static inline unsigned char disp_hcms29xx_bitswap
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| swap data bits in byte (7<->0 , 6<->1 etc) |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
unsigned char byte
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
unsigned char result = 0;
|
||||
int smsk,dmsk;
|
||||
for (smsk = 0x01,dmsk=0x80;
|
||||
smsk < 0x100;
|
||||
smsk<<=1 ,dmsk>>=1) {
|
||||
if ((byte & smsk) != 0) {
|
||||
result |= (unsigned char) dmsk;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_status_code disp_hcms29xx_copy_font
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| copy font data from source to dest font structure |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
disp_font_t src, /* source font */
|
||||
struct disp_font_base *dst, /* ptr to destination font */
|
||||
int shift_cnt, /* shift count for font */
|
||||
bool do_rotate /* rotate font, if true */
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
char *alloc_next = (char *)dst;
|
||||
size_t glyph_idx = 0;
|
||||
int glyph_size;
|
||||
unsigned char byte;
|
||||
int bcnt;
|
||||
|
||||
/*
|
||||
* check parameters
|
||||
*/
|
||||
if ((rc == RTEMS_SUCCESSFUL) &&
|
||||
((src == NULL) ||
|
||||
(dst == NULL))) {
|
||||
rc = RTEMS_INVALID_ADDRESS;
|
||||
}
|
||||
/*
|
||||
* copy font_base structure
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
*dst = *src;
|
||||
alloc_next += sizeof(*dst);
|
||||
}
|
||||
/*
|
||||
* for all glyphs: assign own glyph memory
|
||||
*/
|
||||
glyph_idx = 0;
|
||||
while ((rc == RTEMS_SUCCESSFUL) &&
|
||||
glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0]))) {
|
||||
if (src->latin1[glyph_idx] != NULL) {
|
||||
/*
|
||||
* allocate space for glyph
|
||||
*/
|
||||
dst->latin1[glyph_idx] = (struct disp_font_glyph *)alloc_next;
|
||||
alloc_next += sizeof(*(dst->latin1[glyph_idx]));
|
||||
/*
|
||||
* copy source values.
|
||||
* Note: bitmap will be reassigned later
|
||||
*/
|
||||
*(struct disp_font_glyph *)(dst->latin1[glyph_idx]) =
|
||||
*(src->latin1[glyph_idx]);
|
||||
}
|
||||
else {
|
||||
dst->latin1[glyph_idx] = NULL;
|
||||
}
|
||||
glyph_idx++;
|
||||
}
|
||||
|
||||
/*
|
||||
* for all glyphs: reassign bitmap
|
||||
*/
|
||||
glyph_idx = 0;
|
||||
while ((rc == RTEMS_SUCCESSFUL) &&
|
||||
glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0]))) {
|
||||
if (src->latin1[glyph_idx] != NULL) {
|
||||
glyph_size = src->latin1[glyph_idx]->bb.w;
|
||||
/*
|
||||
* allocate space for glyph_bitmap
|
||||
*/
|
||||
dst->latin1[glyph_idx]->bitmap = (const unsigned char *) alloc_next;
|
||||
alloc_next += glyph_size;
|
||||
/*
|
||||
* copy/transform bitmap
|
||||
*/
|
||||
for (bcnt = 0;bcnt < glyph_size;bcnt++) {
|
||||
if (do_rotate) {
|
||||
byte = src->latin1[glyph_idx]->bitmap[glyph_size - 1 - bcnt];
|
||||
byte = disp_hcms29xx_bitswap(byte);
|
||||
}
|
||||
else {
|
||||
byte = src->latin1[glyph_idx]->bitmap[bcnt];
|
||||
}
|
||||
if (shift_cnt < 0) {
|
||||
byte = byte >> shift_cnt;
|
||||
}
|
||||
else if (shift_cnt > 0) {
|
||||
byte = byte >> shift_cnt;
|
||||
}
|
||||
((unsigned char *)(dst->latin1[glyph_idx]->bitmap))[bcnt] = byte;
|
||||
}
|
||||
}
|
||||
glyph_idx++;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_status_code disp_hcms29xx_alloc_copy_font
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| copy font data from source to dest font structure, alloc all data |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const disp_font_t src, /* source font */
|
||||
disp_font_t *dst, /* ptr to destination font */
|
||||
int shift_cnt, /* shift count for font */
|
||||
bool do_rotate /* rotate font, if true */
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
size_t src_size = 0;
|
||||
/*
|
||||
* check parameters
|
||||
*/
|
||||
if ((rc == RTEMS_SUCCESSFUL) &&
|
||||
((src == NULL)
|
||||
|| (dst == NULL))) {
|
||||
rc = RTEMS_INVALID_ADDRESS;
|
||||
}
|
||||
/*
|
||||
* determine size of source data
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = disp_hcms29xx_font_struct_size(src,&src_size);
|
||||
}
|
||||
/*
|
||||
* allocate proper data area
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
*dst = malloc(src_size);
|
||||
if (*dst == NULL) {
|
||||
rc = RTEMS_UNSATISFIED;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* scan through source data, copy to dest
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = disp_hcms29xx_copy_font(src,*dst,shift_cnt,do_rotate);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=========================================
|
||||
* SPI communication functions
|
||||
*/
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_status_code disp_hcms29xx_send_to_display
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| request access semaphore to SPI, prepare buffer descriptors, start |
|
||||
| transfer via SPI to display |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
disp_hcms29xx_drv_t *softc_ptr,
|
||||
const volatile char *disp_buffer /* start of chars to display (4 chars or 'til \0)*/
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
bool char_avail;
|
||||
const struct disp_font_glyph *glyph_ptr;
|
||||
disp_font_t curr_font;
|
||||
int i, ret_cnt;
|
||||
unsigned char c;
|
||||
|
||||
/*
|
||||
* select device, set transfer mode, address device
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_start(softc_ptr->disp_param.minor);
|
||||
}
|
||||
/*
|
||||
* set transfer mode
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = -rtems_libi2c_ioctl(softc_ptr->disp_param.minor,
|
||||
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
|
||||
&spi_disphcms29xx_tfr_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* address device
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_addr(softc_ptr->disp_param.minor,true);
|
||||
}
|
||||
|
||||
/*
|
||||
* send data
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
curr_font =
|
||||
softc_ptr->disp_param.rotate
|
||||
? disp_hcms29xx_font_rotate
|
||||
: disp_hcms29xx_font_normal;
|
||||
|
||||
char_avail = true;
|
||||
/*
|
||||
* FIXME: for rotated display, write last character first...
|
||||
* maybe we should copy everything to a common buffer and use
|
||||
* ONE SPI transfer?
|
||||
*/
|
||||
for (i = 0;
|
||||
((rc == RTEMS_SUCCESSFUL) &&
|
||||
(i < DISP_HCMS29XX_DIGIT_CNT));
|
||||
i++) {
|
||||
/* test for end of string... */
|
||||
c = disp_buffer[i]; /* perform consistent read of disp_buffer */
|
||||
if (char_avail && (c == '\0')) {
|
||||
char_avail = false;
|
||||
}
|
||||
glyph_ptr = (char_avail
|
||||
? curr_font->latin1[c]
|
||||
: NULL);
|
||||
if (glyph_ptr == NULL) {
|
||||
glyph_ptr = curr_font->latin1[' '];
|
||||
}
|
||||
|
||||
/*
|
||||
* send 5 bytes from (char *)glyph_ptr->bitmap to SPI
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
ret_cnt = rtems_libi2c_write_bytes(softc_ptr->disp_param.minor,
|
||||
glyph_ptr->bitmap,5);
|
||||
if (ret_cnt < 0) {
|
||||
rc = -ret_cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* finish transfer
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_stop(softc_ptr->disp_param.minor);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_status_code disp_hcms29xx_send_to_control
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| request access semaphore to SPI, prepare buffer descriptors, start |
|
||||
| transfer via SPI to display |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
disp_hcms29xx_drv_t *softc_ptr,
|
||||
int pwm, /* value for pwm of LEDs, 0..15 */
|
||||
int peak, /* value for peak current for LEDs, 0..3 */
|
||||
int sleep, /* value to make display "sleep" (0..1 */
|
||||
int div, /* divider for external osc input, unused here */
|
||||
int chain /* mode to drive other displays, unused here */
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
int run, ret_cnt;
|
||||
uint8_t ctrl_buffer;
|
||||
|
||||
/* two accesses, control word 0 and 1 */
|
||||
for (run = 0;
|
||||
((rc == RTEMS_SUCCESSFUL) && (run <= 1));
|
||||
run++) {
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
if (run == 0) {
|
||||
ctrl_buffer =
|
||||
(0 << 7) |
|
||||
((sleep & 0x01) << 6) |
|
||||
((peak & 0x03) << 4) |
|
||||
((pwm & 0x0f) << 0);
|
||||
}
|
||||
else {
|
||||
ctrl_buffer =
|
||||
(1 << 7) |
|
||||
((div & 0x01) << 1) |
|
||||
((chain & 0x01) << 0);
|
||||
}
|
||||
/*
|
||||
* select device, set transfer mode, address device
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_start(softc_ptr->disp_param.minor);
|
||||
}
|
||||
/*
|
||||
* set transfer mode
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = -rtems_libi2c_ioctl(softc_ptr->disp_param.minor,
|
||||
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
|
||||
&spi_disphcms29xx_tfr_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* address device
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_addr(softc_ptr->disp_param.minor,true);
|
||||
}
|
||||
|
||||
/*
|
||||
* send 1 byte from ctrl_buffer
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
ret_cnt = rtems_libi2c_write_bytes(softc_ptr->disp_param.minor,
|
||||
&ctrl_buffer,1);
|
||||
if (ret_cnt < 0) {
|
||||
rc = -ret_cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* next run ... */
|
||||
|
||||
/*
|
||||
* finish transfer
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_stop(softc_ptr->disp_param.minor);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_timer_service_routine disp_hcms29xx_timer_sr
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| this task updates the string in the display |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
(
|
||||
rtems_id id, /* ID of timer, not used */
|
||||
void * arg /* calling arg: softc_ptr */
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| <none used> |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
disp_hcms29xx_drv_t *softc_ptr = arg;
|
||||
|
||||
rtems_event_send(softc_ptr->disp_param.task_id, DISP_HCMS29XX_EVENT_TIMER);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_task disp_hcms29xx_update_task
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| this task updates the string in the display |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_task_argument argument
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| <never exits> |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
rtems_event_set my_events;
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
int disp_offset = 0;
|
||||
rtems_id disp_hcms29xx_timer_id;
|
||||
disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
|
||||
|
||||
/*
|
||||
* initialize display:
|
||||
*/
|
||||
/*
|
||||
* set control attributes for display
|
||||
* maximum brightness...
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = disp_hcms29xx_send_to_control(softc_ptr,
|
||||
14,3,1,0,0);/* pwm/peak/nosleep/div/chain */
|
||||
}
|
||||
|
||||
/*
|
||||
* set display to blank
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = disp_hcms29xx_send_to_display(softc_ptr,
|
||||
"");
|
||||
}
|
||||
|
||||
/*
|
||||
* create timer for scrolling
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_timer_create(DISP_HCMS29XX_TIMER_NAME,
|
||||
&disp_hcms29xx_timer_id);
|
||||
}
|
||||
|
||||
while (rc == RTEMS_SUCCESSFUL) {
|
||||
/*
|
||||
* wait for any event
|
||||
*/
|
||||
rc = rtems_event_receive(DISP_HCMS29XX_EVENT_NEWSTR |
|
||||
DISP_HCMS29XX_EVENT_TIMER ,
|
||||
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
||||
RTEMS_NO_TIMEOUT,
|
||||
&my_events);
|
||||
if (my_events & DISP_HCMS29XX_EVENT_NEWSTR) {
|
||||
/*
|
||||
* fetch new string consistently into local buffer
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_semaphore_obtain(softc_ptr->disp_param.trns_sema_id,
|
||||
RTEMS_WAIT,RTEMS_NO_TIMEOUT);
|
||||
}
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
strncpy(softc_ptr->disp_param.disp_buffer,
|
||||
softc_ptr->disp_param.trns_buffer,
|
||||
sizeof(softc_ptr->disp_param.disp_buffer));
|
||||
softc_ptr->disp_param.disp_buffer[sizeof(softc_ptr->disp_param.disp_buffer)-1] = '\0';
|
||||
softc_ptr->disp_param.disp_buf_cnt =
|
||||
(int) strlen(softc_ptr->disp_param.disp_buffer);
|
||||
}
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_semaphore_release(softc_ptr->disp_param.trns_sema_id);
|
||||
}
|
||||
/*
|
||||
* set initial offset to negative value
|
||||
* to make string static for some ticks
|
||||
*/
|
||||
disp_offset = -4;
|
||||
}
|
||||
if (my_events & DISP_HCMS29XX_EVENT_TIMER) {
|
||||
/*
|
||||
* increase disp_offset, if possible, otherwise reset it
|
||||
*/
|
||||
if ((disp_offset < 0) ||
|
||||
(disp_offset < softc_ptr->disp_param.disp_buf_cnt-
|
||||
DISP_HCMS29XX_DIGIT_CNT/2)) {
|
||||
disp_offset++;
|
||||
}
|
||||
else {
|
||||
disp_offset = -4;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* display string, starting from disp_offset
|
||||
*/
|
||||
if (disp_offset < 0) {
|
||||
rc = disp_hcms29xx_send_to_display(softc_ptr,
|
||||
softc_ptr->disp_param.disp_buffer);
|
||||
}
|
||||
else if (disp_offset
|
||||
< (softc_ptr->disp_param.disp_buf_cnt - DISP_HCMS29XX_DIGIT_CNT)) {
|
||||
rc = disp_hcms29xx_send_to_display(softc_ptr,
|
||||
softc_ptr->disp_param.disp_buffer+disp_offset);
|
||||
}
|
||||
else {
|
||||
rc = disp_hcms29xx_send_to_display(softc_ptr,
|
||||
softc_ptr->disp_param.disp_buffer
|
||||
+ softc_ptr->disp_param.disp_buf_cnt
|
||||
- DISP_HCMS29XX_DIGIT_CNT);
|
||||
}
|
||||
/*
|
||||
* activate timer, if needed
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
if (softc_ptr->disp_param.disp_buf_cnt > DISP_HCMS29XX_DIGIT_CNT) {
|
||||
rc = rtems_timer_fire_after(disp_hcms29xx_timer_id,
|
||||
50,
|
||||
disp_hcms29xx_timer_sr,
|
||||
NULL);
|
||||
}
|
||||
else {
|
||||
rc = rtems_timer_cancel(disp_hcms29xx_timer_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* FIXME: display task is dead...
|
||||
*/
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_status_code disp_hcms29xx_update
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| move given string to display task |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
disp_hcms29xx_drv_t *softc_ptr,
|
||||
const char *src
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
|
||||
/*
|
||||
* obtain trns semaphore
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_semaphore_obtain(softc_ptr->disp_param.trns_sema_id,
|
||||
RTEMS_WAIT,RTEMS_NO_TIMEOUT);
|
||||
}
|
||||
/*
|
||||
* copy string...
|
||||
*/
|
||||
strncpy(softc_ptr->disp_param.trns_buffer,src,
|
||||
sizeof(softc_ptr->disp_param.trns_buffer));
|
||||
softc_ptr->disp_param.trns_buffer[sizeof(softc_ptr->disp_param.trns_buffer)-1] = '\0';
|
||||
|
||||
/*
|
||||
* release trns semaphore
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_semaphore_release(softc_ptr->disp_param.trns_sema_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* send event to task
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_event_send(softc_ptr->disp_param.task_id,
|
||||
DISP_HCMS29XX_EVENT_NEWSTR);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_driver disp_hcms29xx_dev_initialize
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| prepare the display device driver to accept write calls |
|
||||
| register device with its name |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
/*
|
||||
* Initialize and register the device
|
||||
*/
|
||||
{
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
|
||||
|
||||
/*
|
||||
* initialize font management
|
||||
* FIXME: check, that default glyph exists
|
||||
* FIXME: check font size to be 5x7
|
||||
*/
|
||||
/*
|
||||
* translate font according to direction/baseline
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = disp_hcms29xx_alloc_copy_font(
|
||||
&FONT_BASE,
|
||||
&disp_hcms29xx_font_normal,
|
||||
FONT_BASE.descent, /* shift to visibility... */
|
||||
FALSE); /* do not rotate */
|
||||
}
|
||||
/* FIXME: translate font for rotation */
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = disp_hcms29xx_alloc_copy_font(&FONT_BASE,
|
||||
&disp_hcms29xx_font_rotate,
|
||||
0, /* do not shift */
|
||||
true); /* rotate font */
|
||||
}
|
||||
/*
|
||||
* create the trns_buffer semaphore
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_semaphore_create (DISP_HCMS29XX_TRNS_SEMA_NAME,1,
|
||||
RTEMS_PRIORITY
|
||||
|RTEMS_BINARY_SEMAPHORE
|
||||
|RTEMS_INHERIT_PRIORITY
|
||||
|RTEMS_NO_PRIORITY_CEILING
|
||||
|RTEMS_LOCAL,
|
||||
0,
|
||||
&softc_ptr->disp_param.trns_sema_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* create and start display task
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_task_create(DISP_HCMS29XX_TASK_NAME,
|
||||
20,
|
||||
RTEMS_MINIMUM_STACK_SIZE,
|
||||
RTEMS_INTERRUPT_LEVEL(0) | RTEMS_TIMESLICE,
|
||||
RTEMS_DEFAULT_ATTRIBUTES,
|
||||
&softc_ptr->disp_param.task_id);
|
||||
}
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_task_start(softc_ptr->disp_param.task_id,
|
||||
disp_hcms29xx_update_task,0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_driver disp_hcms29xx_dev_open
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| open the display device |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
|
||||
/*
|
||||
* ensure, that disp_hcms29xx device is assumed to be empty
|
||||
*/
|
||||
softc_ptr->disp_param.dev_buf_cnt = 0;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_driver disp_hcms29xx_dev_write
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| write to display device |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
rtems_libio_rw_args_t *args = arg;
|
||||
uint32_t cnt;
|
||||
disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
|
||||
|
||||
for (cnt = 0;cnt < args->count;cnt++) {
|
||||
/*
|
||||
* accumulate characters written into display dev buffer
|
||||
*/
|
||||
if (((softc_ptr->disp_param.dev_buf_cnt > 0)
|
||||
&&((args->buffer[cnt] == '\n')
|
||||
|| (args->buffer[cnt] == '\0'))
|
||||
)
|
||||
||( softc_ptr->disp_param.dev_buf_cnt >=
|
||||
(int) sizeof(softc_ptr->disp_param.dev_buffer) - 1)) {
|
||||
softc_ptr->disp_param.dev_buffer[softc_ptr->disp_param.dev_buf_cnt] = '\0';
|
||||
/*
|
||||
* transfer string to display string, redisplay it...
|
||||
*/
|
||||
disp_hcms29xx_update(softc_ptr,softc_ptr->disp_param.dev_buffer);
|
||||
softc_ptr->disp_param.dev_buf_cnt = 0;
|
||||
}
|
||||
/*
|
||||
* write to dev_buf, if '\n' occured or display device buffer is full
|
||||
*/
|
||||
if ((args->buffer[cnt] != '\n') &&
|
||||
(args->buffer[cnt] != '\0')) {
|
||||
softc_ptr->disp_param.dev_buffer[softc_ptr->disp_param.dev_buf_cnt++] =
|
||||
args->buffer[cnt];
|
||||
}
|
||||
}
|
||||
args->bytes_moved = args->count;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_driver disp_hcms29xx_dev_close
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| close the display device |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| rtems_status_code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* driver operation tables
|
||||
*/
|
||||
static rtems_driver_address_table disp_hcms29xx_ops = {
|
||||
.initialization_entry = disp_hcms29xx_dev_initialize,
|
||||
.open_entry = disp_hcms29xx_dev_open,
|
||||
.write_entry = disp_hcms29xx_dev_write,
|
||||
.close_entry = disp_hcms29xx_dev_close
|
||||
};
|
||||
|
||||
|
||||
static disp_hcms29xx_drv_t disp_hcms29xx_drv_tbl = {
|
||||
{/* public fields */
|
||||
.ops = &disp_hcms29xx_ops,
|
||||
.size = sizeof (disp_hcms29xx_drv_t),
|
||||
},
|
||||
{ /* our private fields */
|
||||
0,
|
||||
{ 0 },
|
||||
0,
|
||||
{ 0 },
|
||||
{ 0 },
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
rtems_libi2c_drv_t *disp_hcms29xx_driver_descriptor =
|
||||
&disp_hcms29xx_drv_tbl.libi2c_drv_entry;
|
||||
|
||||
1820
bsps/shared/dev/display/font_hcms29xx.c
Normal file
1820
bsps/shared/dev/display/font_hcms29xx.c
Normal file
File diff suppressed because it is too large
Load Diff
36
bsps/shared/dev/display/font_hcms29xx.h
Normal file
36
bsps/shared/dev/display/font_hcms29xx.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*===============================================================*\
|
||||
| Project: display driver for HCMS29xx |
|
||||
+-----------------------------------------------------------------+
|
||||
| File: font_hcms29xx.h |
|
||||
+-----------------------------------------------------------------+
|
||||
| Copyright (c) 2008 |
|
||||
| Embedded Brains GmbH |
|
||||
| Obere Lagerstr. 30 |
|
||||
| D-82178 Puchheim |
|
||||
| Germany |
|
||||
| rtems@embedded-brains.de |
|
||||
+-----------------------------------------------------------------+
|
||||
| The license and distribution terms for this file may be |
|
||||
| found in the file LICENSE in this distribution or at |
|
||||
| http://www.rtems.org/license/LICENSE. |
|
||||
+-----------------------------------------------------------------+
|
||||
| This file declares the 5x7 bit font used in disp_hcms29xx |
|
||||
\*===============================================================*/
|
||||
|
||||
#ifndef FONT_HCMS29XX_H
|
||||
#define FONT_HCMS29XX_H
|
||||
|
||||
#include "disp_fonts.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct disp_font_base font_hcms29xx_base;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* not defined FONT_HCMS29XX_H */
|
||||
473
bsps/shared/dev/flash/am29lv160.c
Normal file
473
bsps/shared/dev/flash/am29lv160.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* RTEMS Project (http://www.rtems.org/)
|
||||
*
|
||||
* Copyright 2007 Chris Johns (chrisj@rtems.org)
|
||||
*/
|
||||
/**
|
||||
* Provide flash support for the AM26LV160 device.
|
||||
*
|
||||
* The M29W160D is the same device.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#include <libchip/am29lv160.h>
|
||||
|
||||
#ifndef AM26LV160_ERROR_TRACE
|
||||
#define AM26LV160_ERROR_TRACE (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Boot blocks at the top
|
||||
*/
|
||||
const rtems_fdisk_segment_desc rtems_am29lv160t_segments[4] =
|
||||
{
|
||||
{
|
||||
.count = 31,
|
||||
.segment = 0,
|
||||
.offset = 0x00000000,
|
||||
.size = RTEMS_FDISK_KBYTES (64)
|
||||
},
|
||||
{
|
||||
.count = 1,
|
||||
.segment = 31,
|
||||
.offset = 0x001f0000,
|
||||
.size = RTEMS_FDISK_KBYTES (32)
|
||||
},
|
||||
{
|
||||
.count = 2,
|
||||
.segment = 32,
|
||||
.offset = 0x001f8000,
|
||||
.size = RTEMS_FDISK_KBYTES (8)
|
||||
},
|
||||
{
|
||||
.count = 1,
|
||||
.segment = 34,
|
||||
.offset = 0x001fc000,
|
||||
.size = RTEMS_FDISK_KBYTES (16)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Boot blocks at the bottom.
|
||||
*/
|
||||
const rtems_fdisk_segment_desc rtems_am29lv160b_segments[] =
|
||||
{
|
||||
{
|
||||
.count = 1,
|
||||
.segment = 0,
|
||||
.offset = 0x00000000,
|
||||
.size = RTEMS_FDISK_KBYTES (16)
|
||||
},
|
||||
{
|
||||
. count = 2,
|
||||
.segment = 1,
|
||||
.offset = 0x00004000,
|
||||
.size = RTEMS_FDISK_KBYTES (8)
|
||||
},
|
||||
{
|
||||
.count = 1,
|
||||
.segment = 3,
|
||||
.offset = 0x00008000,
|
||||
.size = RTEMS_FDISK_KBYTES (32)
|
||||
},
|
||||
{
|
||||
.count = 31,
|
||||
.segment = 4,
|
||||
.offset = 0x00010000,
|
||||
.size = RTEMS_FDISK_KBYTES (64)
|
||||
}
|
||||
};
|
||||
|
||||
static int
|
||||
rtems_am29lv160_blank (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment,
|
||||
uint32_t offset,
|
||||
uint32_t size)
|
||||
{
|
||||
const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
|
||||
volatile uint8_t* seg_8 = ac->base;
|
||||
volatile uint32_t* seg_32;
|
||||
uint32_t count;
|
||||
|
||||
offset += sd->offset + (segment - sd->segment) * sd->size;
|
||||
|
||||
seg_8 += offset;
|
||||
|
||||
count = offset & (sizeof (uint32_t) - 1);
|
||||
size -= count;
|
||||
|
||||
while (count--)
|
||||
if (*seg_8++ != 0xff)
|
||||
{
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: blank check error: %p = 0x%02x\n",
|
||||
seg_8 - 1, *(seg_8 - 1));
|
||||
#endif
|
||||
return EIO;
|
||||
}
|
||||
|
||||
seg_32 = (volatile uint32_t*) seg_8;
|
||||
|
||||
count = size / sizeof (uint32_t);
|
||||
size -= count * sizeof (uint32_t);
|
||||
|
||||
while (count--)
|
||||
if (*seg_32++ != 0xffffffff)
|
||||
{
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: blank check error: %p = 0x%08lx\n",
|
||||
seg_32 - 1, *(seg_32 - 1));
|
||||
#endif
|
||||
return EIO;
|
||||
}
|
||||
|
||||
seg_8 = (volatile uint8_t*) seg_32;
|
||||
|
||||
while (size--)
|
||||
if (*seg_8++ != 0xff)
|
||||
{
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: blank check error: %p = 0x%02x\n",
|
||||
seg_8 - 1, *(seg_8 - 1));
|
||||
#endif
|
||||
return EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_verify (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment,
|
||||
uint32_t offset,
|
||||
const void* buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
|
||||
const uint8_t* addr = ac->base;
|
||||
|
||||
addr += (sd->offset + (segment - sd->segment) * sd->size) + offset;
|
||||
|
||||
if (memcmp (addr, buffer, size) != 0)
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_toggle_wait_8 (volatile uint8_t* status)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
volatile uint8_t status1 = *status;
|
||||
volatile uint8_t status2 = *status;
|
||||
|
||||
if (((status1 ^ status2) & (1 << 6)) == 0)
|
||||
return 0;
|
||||
|
||||
if ((status1 & (1 << 5)) != 0)
|
||||
{
|
||||
status1 = *status;
|
||||
status2 = *status;
|
||||
|
||||
if (((status1 ^ status2) & (1 << 6)) == 0)
|
||||
return 0;
|
||||
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: error bit detected: %p = 0x%04x\n",
|
||||
status, status1);
|
||||
#endif
|
||||
|
||||
*status = 0xf0;
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_toggle_wait_16 (volatile uint16_t* status)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
volatile uint16_t status1 = *status;
|
||||
volatile uint16_t status2 = *status;
|
||||
|
||||
if (((status1 ^ status2) & (1 << 6)) == 0)
|
||||
return 0;
|
||||
|
||||
if ((status1 & (1 << 5)) != 0)
|
||||
{
|
||||
status1 = *status;
|
||||
status2 = *status;
|
||||
|
||||
if (((status1 ^ status2) & (1 << 6)) == 0)
|
||||
return 0;
|
||||
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: error bit detected: %p = 0x%04x/0x%04x\n",
|
||||
status, status1, status2);
|
||||
#endif
|
||||
|
||||
*status = 0xf0;
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_write_data_8 (volatile uint8_t* base,
|
||||
uint32_t offset,
|
||||
const uint8_t* data,
|
||||
uint32_t size)
|
||||
{
|
||||
volatile uint8_t* seg = base + offset;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
|
||||
while (size)
|
||||
{
|
||||
rtems_interrupt_disable (level);
|
||||
*(base + 0xaaa) = 0xaa;
|
||||
*(base + 0x555) = 0x55;
|
||||
*(base + 0xaaa) = 0xa0;
|
||||
*seg = *data++;
|
||||
rtems_interrupt_enable (level);
|
||||
if (rtems_am29lv160_toggle_wait_8 (seg++) != 0)
|
||||
return EIO;
|
||||
size--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_write_data_16 (volatile uint16_t* base,
|
||||
uint32_t offset,
|
||||
const uint16_t* data,
|
||||
uint32_t size)
|
||||
{
|
||||
volatile uint16_t* seg = base + (offset / 2);
|
||||
rtems_interrupt_level level;
|
||||
|
||||
size /= 2;
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
|
||||
while (size)
|
||||
{
|
||||
rtems_interrupt_disable (level);
|
||||
*(base + 0x555) = 0xaa;
|
||||
*(base + 0x2aa) = 0x55;
|
||||
*(base + 0x555) = 0xa0;
|
||||
*seg = *data++;
|
||||
rtems_interrupt_enable (level);
|
||||
if (rtems_am29lv160_toggle_wait_16 (seg++) != 0)
|
||||
return EIO;
|
||||
size--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_read (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment,
|
||||
uint32_t offset,
|
||||
void* buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
unsigned char* addr =
|
||||
rtems_am29lv160_configuration[device].base +
|
||||
sd->offset + ((segment - sd->segment) * sd->size) + offset;
|
||||
memcpy (buffer, addr, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @todo Fix the odd alignment and odd sizes.
|
||||
*/
|
||||
static int
|
||||
rtems_am29lv160_write (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment,
|
||||
uint32_t offset,
|
||||
const void* buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
int ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
|
||||
uint32_t soffset;
|
||||
|
||||
soffset = offset + sd->offset + ((segment - sd->segment) * sd->size);
|
||||
|
||||
if (offset & 1)
|
||||
printf ("rtems_am29lv160_write: offset is odd\n");
|
||||
|
||||
if (size & 1)
|
||||
printf ("rtems_am29lv160_write: size is odd\n");
|
||||
|
||||
if (ac->bus_8bit)
|
||||
ret = rtems_am29lv160_write_data_8 (ac->base, soffset, buffer, size);
|
||||
else
|
||||
ret = rtems_am29lv160_write_data_16 (ac->base, soffset, buffer, size);
|
||||
|
||||
/*
|
||||
* Verify the write worked.
|
||||
*/
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
if (ret)
|
||||
printf ("AM26LV160: verify failed: %ld-%ld-%08lx: s=%ld\n",
|
||||
device, segment, offset, size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_erase (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment)
|
||||
{
|
||||
int ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
|
||||
if (ret != 0)
|
||||
{
|
||||
const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
|
||||
uint32_t offset;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
offset = sd->offset + ((segment - sd->segment) * sd->size);
|
||||
|
||||
if (ac->bus_8bit)
|
||||
{
|
||||
volatile uint8_t* base = ac->base;
|
||||
volatile uint8_t* seg = base + offset;
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
rtems_interrupt_disable (level);
|
||||
*base = 0xf0;
|
||||
*(base + 0xaaa) = 0xaa;
|
||||
*(base + 0x555) = 0x55;
|
||||
*(base + 0xaaa) = 0x80;
|
||||
*(base + 0xaaa) = 0xaa;
|
||||
*(base + 0x555) = 0x55;
|
||||
*seg = 0x30;
|
||||
rtems_interrupt_enable (level);
|
||||
|
||||
ret = rtems_am29lv160_toggle_wait_8 (seg);
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
}
|
||||
else
|
||||
{
|
||||
volatile uint16_t* base = ac->base;
|
||||
volatile uint16_t* seg = base + (offset / 2);
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
rtems_interrupt_disable (level);
|
||||
*base = 0xf0;
|
||||
*(base + 0x555) = 0xaa;
|
||||
*(base + 0x2aa) = 0x55;
|
||||
*(base + 0x555) = 0x80;
|
||||
*(base + 0x555) = 0xaa;
|
||||
*(base + 0x2aa) = 0x55;
|
||||
*seg = 0x30;
|
||||
rtems_interrupt_enable (level);
|
||||
|
||||
ret = rtems_am29lv160_toggle_wait_16 (seg);
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the erase worked.
|
||||
*/
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
if (ret)
|
||||
printf ("AM26LV160: erase failed: %ld-%ld\n", device, segment);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_erase_device (const rtems_fdisk_device_desc* dd,
|
||||
uint32_t device)
|
||||
{
|
||||
uint32_t segment;
|
||||
|
||||
for (segment = 0; segment < dd->segment_count; segment++)
|
||||
{
|
||||
uint32_t seg_segment;
|
||||
|
||||
for (seg_segment = 0;
|
||||
seg_segment < dd->segments[segment].count;
|
||||
seg_segment++)
|
||||
{
|
||||
int ret = rtems_am29lv160_erase (&dd->segments[segment],
|
||||
device,
|
||||
segment + seg_segment);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const rtems_fdisk_driver_handlers rtems_am29lv160_handlers =
|
||||
{
|
||||
.read = rtems_am29lv160_read,
|
||||
.write = rtems_am29lv160_write,
|
||||
.blank = rtems_am29lv160_blank,
|
||||
.verify = rtems_am29lv160_verify,
|
||||
.erase = rtems_am29lv160_erase,
|
||||
.erase_device = rtems_am29lv160_erase_device
|
||||
};
|
||||
177
bsps/shared/dev/i2c/i2c-2b-eeprom.c
Normal file
177
bsps/shared/dev/i2c/i2c-2b-eeprom.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/* Trivial i2c driver for reading "2-byte eeproms".
|
||||
* On 'open' the read-pointer is reset to 0, subsequent
|
||||
* read operations slurp data from there...
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authorship
|
||||
* ----------
|
||||
* This software was created by
|
||||
* Till Straumann <strauman@slac.stanford.edu>, 2005,
|
||||
* Stanford Linear Accelerator Center, Stanford University.
|
||||
*
|
||||
* Acknowledgement of sponsorship
|
||||
* ------------------------------
|
||||
* This software was produced by
|
||||
* the Stanford Linear Accelerator Center, Stanford University,
|
||||
* under Contract DE-AC03-76SFO0515 with the Department of Energy.
|
||||
*
|
||||
* Government disclaimer of liability
|
||||
* ----------------------------------
|
||||
* Neither the United States nor the United States Department of Energy,
|
||||
* nor any of their employees, makes any warranty, express or implied, or
|
||||
* assumes any legal liability or responsibility for the accuracy,
|
||||
* completeness, or usefulness of any data, apparatus, product, or process
|
||||
* disclosed, or represents that its use would not infringe privately owned
|
||||
* rights.
|
||||
*
|
||||
* Stanford disclaimer of liability
|
||||
* --------------------------------
|
||||
* Stanford University makes no representations or warranties, express or
|
||||
* implied, nor assumes any liability for the use of this software.
|
||||
*
|
||||
* Stanford disclaimer of copyright
|
||||
* --------------------------------
|
||||
* Stanford University, owner of the copyright, hereby disclaims its
|
||||
* copyright and all other rights in this software. Hence, anyone may
|
||||
* freely use it for any purpose without restriction.
|
||||
*
|
||||
* Maintenance of notices
|
||||
* ----------------------
|
||||
* In the interest of clarity regarding the origin and status of this
|
||||
* SLAC software, this and all the preceding Stanford University notices
|
||||
* are to remain affixed to any copy or derivative of this software made
|
||||
* or distributed by the recipient and are to be affixed to any copy of
|
||||
* software made or distributed by the recipient that contains a copy or
|
||||
* derivative of this software.
|
||||
*
|
||||
* ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
|
||||
*/
|
||||
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libi2c.h>
|
||||
|
||||
#include <libchip/i2c-2b-eeprom.h>
|
||||
#include <rtems/libio.h>
|
||||
|
||||
#define EEPROM_PG_SZ 32
|
||||
#define ALGN(x) (((uint32_t)(x) + EEPROM_PG_SZ) & ~(EEPROM_PG_SZ-1))
|
||||
|
||||
static rtems_status_code
|
||||
send_file_ptr (rtems_device_minor_number minor, unsigned pos, int tout)
|
||||
{
|
||||
int sc;
|
||||
unsigned char bytes[2];
|
||||
|
||||
bytes[0] = (pos >> 8) & 0xff;
|
||||
bytes[1] = (pos) & 0xff;
|
||||
|
||||
/* poll addressing the next page; if 'tout' is <=0 we only try once
|
||||
* and return the status. If 'tout' is positive, we try 'tout' times
|
||||
* and return RTEMS_TIMEOUT if it didnt work
|
||||
*/
|
||||
while ((sc = rtems_libi2c_start_write_bytes (minor, bytes, 2)) < 0) {
|
||||
if (--tout <= 0)
|
||||
return tout ? -sc : RTEMS_TIMEOUT;
|
||||
rtems_task_wake_after (1);
|
||||
}
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static rtems_status_code
|
||||
i2c_2b_eeprom_write (rtems_device_major_number major,
|
||||
rtems_device_minor_number minor, void *arg)
|
||||
{
|
||||
rtems_libio_rw_args_t *rwargs = arg;
|
||||
unsigned off = rwargs->offset;
|
||||
int cnt = rwargs->count;
|
||||
unsigned char *buf = (unsigned char *)rwargs->buffer;
|
||||
int sc;
|
||||
unsigned end;
|
||||
int l;
|
||||
|
||||
if (cnt <= 0)
|
||||
return RTEMS_SUCCESSFUL;
|
||||
|
||||
if ((sc = send_file_ptr (minor, off, 0)))
|
||||
return sc;
|
||||
|
||||
do {
|
||||
/* write up to next page boundary */
|
||||
end = ALGN (off);
|
||||
l = end - off;
|
||||
if (l > cnt)
|
||||
l = cnt;
|
||||
|
||||
sc = rtems_libi2c_write_bytes (minor, buf, l);
|
||||
if (sc < 0)
|
||||
return -sc;
|
||||
|
||||
sc = rtems_libi2c_send_stop (minor);
|
||||
if (sc)
|
||||
return sc;
|
||||
|
||||
rwargs->bytes_moved += l;
|
||||
|
||||
buf += l;
|
||||
cnt -= l;
|
||||
off += l;
|
||||
|
||||
/* poll addressing the next page */
|
||||
if ((sc = send_file_ptr (minor, off, 100)))
|
||||
return sc;
|
||||
|
||||
} while (cnt > 0);
|
||||
|
||||
return rtems_libi2c_send_stop (minor);
|
||||
}
|
||||
|
||||
static rtems_status_code
|
||||
i2c_2b_eeprom_read (rtems_device_major_number major,
|
||||
rtems_device_minor_number minor, void *arg)
|
||||
{
|
||||
int sc;
|
||||
rtems_libio_rw_args_t *rwargs = arg;
|
||||
|
||||
if (RTEMS_SUCCESSFUL != (sc = send_file_ptr (minor, rwargs->offset, 0)))
|
||||
return -sc;
|
||||
|
||||
sc = rtems_libi2c_start_read_bytes(
|
||||
minor,
|
||||
(unsigned char *)rwargs->buffer,
|
||||
rwargs->count
|
||||
);
|
||||
|
||||
if (sc < 0) {
|
||||
rwargs->bytes_moved = 0;
|
||||
return -sc;
|
||||
}
|
||||
rwargs->bytes_moved = sc;
|
||||
|
||||
return rtems_libi2c_send_stop (minor);
|
||||
}
|
||||
|
||||
static rtems_driver_address_table myops = {
|
||||
.read_entry = i2c_2b_eeprom_read,
|
||||
.write_entry = i2c_2b_eeprom_write,
|
||||
};
|
||||
|
||||
static rtems_libi2c_drv_t my_drv_tbl = {
|
||||
.ops = &myops,
|
||||
.size = sizeof (my_drv_tbl),
|
||||
};
|
||||
|
||||
/* provide a second table for R/O access */
|
||||
static rtems_driver_address_table my_ro_ops = {
|
||||
.read_entry = i2c_2b_eeprom_read,
|
||||
};
|
||||
|
||||
static rtems_libi2c_drv_t my_ro_drv_tbl = {
|
||||
.ops = &my_ro_ops,
|
||||
.size = sizeof (my_ro_drv_tbl),
|
||||
};
|
||||
|
||||
|
||||
rtems_libi2c_drv_t *i2c_2b_eeprom_driver_descriptor = &my_drv_tbl;
|
||||
rtems_libi2c_drv_t *i2c_2b_eeprom_ro_driver_descriptor = &my_ro_drv_tbl;
|
||||
128
bsps/shared/dev/i2c/i2c-ds1621.c
Normal file
128
bsps/shared/dev/i2c/i2c-ds1621.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/* Trivial i2c driver for the maxim DS1621 temperature sensor;
|
||||
* just implements reading constant conversions with 8-bit
|
||||
* resolution.
|
||||
* Demonstrates the implementation of a i2c high-level driver.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authorship
|
||||
* ----------
|
||||
* This software was created by
|
||||
* Till Straumann <strauman@slac.stanford.edu>, 2005,
|
||||
* Stanford Linear Accelerator Center, Stanford University.
|
||||
*
|
||||
* Acknowledgement of sponsorship
|
||||
* ------------------------------
|
||||
* This software was produced by
|
||||
* the Stanford Linear Accelerator Center, Stanford University,
|
||||
* under Contract DE-AC03-76SFO0515 with the Department of Energy.
|
||||
*
|
||||
* Government disclaimer of liability
|
||||
* ----------------------------------
|
||||
* Neither the United States nor the United States Department of Energy,
|
||||
* nor any of their employees, makes any warranty, express or implied, or
|
||||
* assumes any legal liability or responsibility for the accuracy,
|
||||
* completeness, or usefulness of any data, apparatus, product, or process
|
||||
* disclosed, or represents that its use would not infringe privately owned
|
||||
* rights.
|
||||
*
|
||||
* Stanford disclaimer of liability
|
||||
* --------------------------------
|
||||
* Stanford University makes no representations or warranties, express or
|
||||
* implied, nor assumes any liability for the use of this software.
|
||||
*
|
||||
* Stanford disclaimer of copyright
|
||||
* --------------------------------
|
||||
* Stanford University, owner of the copyright, hereby disclaims its
|
||||
* copyright and all other rights in this software. Hence, anyone may
|
||||
* freely use it for any purpose without restriction.
|
||||
*
|
||||
* Maintenance of notices
|
||||
* ----------------------
|
||||
* In the interest of clarity regarding the origin and status of this
|
||||
* SLAC software, this and all the preceding Stanford University notices
|
||||
* are to remain affixed to any copy or derivative of this software made
|
||||
* or distributed by the recipient and are to be affixed to any copy of
|
||||
* software made or distributed by the recipient that contains a copy or
|
||||
* derivative of this software.
|
||||
*
|
||||
* ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
|
||||
*/
|
||||
#include <rtems.h>
|
||||
#include <rtems/libi2c.h>
|
||||
|
||||
#include <libchip/i2c-ds1621.h>
|
||||
|
||||
#include <rtems/libio.h>
|
||||
|
||||
|
||||
static rtems_status_code
|
||||
ds1621_init (rtems_device_major_number major, rtems_device_minor_number minor,
|
||||
void *arg)
|
||||
{
|
||||
int sc;
|
||||
unsigned char csr[2] = { DS1621_CMD_CSR_ACCESS, 0 }, cmd;
|
||||
|
||||
/* First start command acquires a lock for the bus */
|
||||
|
||||
/* Initialize; switch continuous conversion on */
|
||||
sc = rtems_libi2c_start_write_bytes (minor, csr, 1);
|
||||
if (sc < 0)
|
||||
return -sc;
|
||||
|
||||
sc = rtems_libi2c_start_read_bytes (minor, csr + 1, 1);
|
||||
if (sc < 0)
|
||||
return -sc;
|
||||
|
||||
csr[1] &= ~DS1621_CSR_1SHOT;
|
||||
|
||||
sc = rtems_libi2c_start_write_bytes (minor, csr, 2);
|
||||
if (sc < 0)
|
||||
return -sc;
|
||||
|
||||
/* Start conversion */
|
||||
cmd = DS1621_CMD_START_CONV;
|
||||
|
||||
sc = rtems_libi2c_start_write_bytes (minor, &cmd, 1);
|
||||
if (sc < 0)
|
||||
return -sc;
|
||||
|
||||
/* sending 'stop' relinquishes the bus mutex -- don't hold it
|
||||
* across system calls!
|
||||
*/
|
||||
return rtems_libi2c_send_stop (minor);
|
||||
}
|
||||
|
||||
static rtems_status_code
|
||||
ds1621_read (rtems_device_major_number major, rtems_device_minor_number minor,
|
||||
void *arg)
|
||||
{
|
||||
int sc;
|
||||
rtems_libio_rw_args_t *rwargs = arg;
|
||||
unsigned char cmd = DS1621_CMD_READ_TEMP;
|
||||
|
||||
sc = rtems_libi2c_start_write_bytes (minor, &cmd, 1);
|
||||
if (sc < 0)
|
||||
return -sc;
|
||||
if (sc < 1)
|
||||
return RTEMS_IO_ERROR;
|
||||
sc = rtems_libi2c_start_read_bytes(minor, (unsigned char *)rwargs->buffer, 1);
|
||||
if (sc < 0) {
|
||||
rwargs->bytes_moved = 0;
|
||||
return -sc;
|
||||
}
|
||||
rwargs->bytes_moved = 1;
|
||||
return rtems_libi2c_send_stop (minor);
|
||||
}
|
||||
|
||||
static rtems_driver_address_table myops = {
|
||||
.initialization_entry = ds1621_init,
|
||||
.read_entry = ds1621_read,
|
||||
};
|
||||
|
||||
static rtems_libi2c_drv_t my_drv_tbl = {
|
||||
.ops = &myops,
|
||||
.size = sizeof (my_drv_tbl),
|
||||
};
|
||||
|
||||
rtems_libi2c_drv_t *i2c_ds1621_driver_descriptor = &my_drv_tbl;
|
||||
91
bsps/shared/dev/i2c/i2c-sc620.c
Normal file
91
bsps/shared/dev/i2c/i2c-sc620.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief I2C Driver for SEMTECH SC620 Octal LED Driver
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <libchip/i2c-sc620.h>
|
||||
|
||||
#include <rtems/libio.h>
|
||||
|
||||
#define SC620_REG_COUNT 10
|
||||
|
||||
static rtems_status_code i2c_sc620_write(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_IO_ERROR;
|
||||
rtems_libio_rw_args_t *rw = arg;
|
||||
unsigned char *buf = (unsigned char *) &rw->buffer[0];
|
||||
|
||||
if (rw->count == 2 && buf[0] < SC620_REG_COUNT) {
|
||||
int rv;
|
||||
|
||||
rv = rtems_libi2c_start_write_bytes(
|
||||
minor, buf, 2
|
||||
);
|
||||
if (rv == 2) {
|
||||
sc = rtems_libi2c_send_stop(minor);
|
||||
}
|
||||
}
|
||||
|
||||
rw->bytes_moved = sc == RTEMS_SUCCESSFUL ? 2 : 0;
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
static rtems_status_code i2c_sc620_read(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_IO_ERROR;
|
||||
rtems_libio_rw_args_t *rw = arg;
|
||||
unsigned char *buf = (unsigned char *) &rw->buffer[0];
|
||||
|
||||
if (rw->count == 1 && buf[0] < SC620_REG_COUNT) {
|
||||
int rv;
|
||||
|
||||
rv = rtems_libi2c_start_write_bytes(minor, buf, 1);
|
||||
if (rv == 1) {
|
||||
sc = rtems_libi2c_send_addr(minor, 0);
|
||||
if (sc == RTEMS_SUCCESSFUL) {
|
||||
rv = rtems_libi2c_read_bytes(minor, buf, 1);
|
||||
if (rv == 1) {
|
||||
sc = rtems_libi2c_send_stop(minor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rw->bytes_moved = sc == RTEMS_SUCCESSFUL ? 1 : 0;
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
static rtems_driver_address_table i2c_sc620_ops = {
|
||||
.read_entry = i2c_sc620_read,
|
||||
.write_entry = i2c_sc620_write
|
||||
};
|
||||
|
||||
rtems_libi2c_drv_t i2c_sc620_driver = {
|
||||
.ops = &i2c_sc620_ops,
|
||||
.size = sizeof(i2c_sc620_driver)
|
||||
};
|
||||
60
bsps/shared/dev/i2c/spi-flash-m25p40.c
Normal file
60
bsps/shared/dev/i2c/spi-flash-m25p40.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*===============================================================*\
|
||||
| Project: SPI driver for M25P40 like spi flash device |
|
||||
+-----------------------------------------------------------------+
|
||||
| Copyright (c) 2007 |
|
||||
| Embedded Brains GmbH |
|
||||
| Obere Lagerstr. 30 |
|
||||
| D-82178 Puchheim |
|
||||
| Germany |
|
||||
| rtems@embedded-brains.de |
|
||||
+-----------------------------------------------------------------+
|
||||
| The license and distribution terms for this file may be |
|
||||
| found in the file LICENSE in this distribution or at |
|
||||
| |
|
||||
| http://www.rtems.org/license/LICENSE. |
|
||||
| |
|
||||
+-----------------------------------------------------------------+
|
||||
\*===============================================================*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libi2c.h>
|
||||
|
||||
#include <libchip/spi-flash-m25p40.h>
|
||||
#include <rtems/libio.h>
|
||||
|
||||
|
||||
static spi_memdrv_t spi_flash_m25p40_rw_drv_t = {
|
||||
{/* public fields */
|
||||
.ops = &spi_memdrv_rw_ops, /* operations of general memdrv */
|
||||
.size = sizeof (spi_flash_m25p40_rw_drv_t),
|
||||
},
|
||||
{ /* our private fields */
|
||||
.baudrate = 2000000,
|
||||
.erase_before_program = true,
|
||||
.empty_state = 0xff,
|
||||
.page_size = 256, /* programming page size in bytes */
|
||||
.sector_size = 0x10000, /* 64K - erase sector size in bytes */
|
||||
.mem_size = 0x80000, /* 512K - total capacity in bytes */
|
||||
}
|
||||
};
|
||||
|
||||
rtems_libi2c_drv_t *spi_flash_m25p40_rw_driver_descriptor =
|
||||
&spi_flash_m25p40_rw_drv_t.libi2c_drv_entry;
|
||||
|
||||
static spi_memdrv_t spi_flash_m25p40_ro_drv_t = {
|
||||
{/* public fields */
|
||||
.ops = &spi_memdrv_ro_ops, /* operations of general memdrv */
|
||||
.size = sizeof (spi_flash_m25p40_ro_drv_t),
|
||||
},
|
||||
{ /* our private fields */
|
||||
.baudrate = 2000000,
|
||||
.erase_before_program = true,
|
||||
.empty_state = 0xff,
|
||||
.page_size = 256, /* programming page size in bytes */
|
||||
.sector_size = 0x10000, /* 64K erase sector size in bytes */
|
||||
.mem_size = 0x80000, /* 512K total capacity in bytes */
|
||||
}
|
||||
};
|
||||
|
||||
rtems_libi2c_drv_t *spi_flash_m25p40_ro_driver_descriptor =
|
||||
&spi_flash_m25p40_ro_drv_t.libi2c_drv_entry;
|
||||
60
bsps/shared/dev/i2c/spi-fram-fm25l256.c
Normal file
60
bsps/shared/dev/i2c/spi-fram-fm25l256.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*===============================================================*\
|
||||
| Project: SPI driver for FM25L256 like spi fram device |
|
||||
+-----------------------------------------------------------------+
|
||||
| Copyright (c) 2008 |
|
||||
| Embedded Brains GmbH |
|
||||
| Obere Lagerstr. 30 |
|
||||
| D-82178 Puchheim |
|
||||
| Germany |
|
||||
| rtems@embedded-brains.de |
|
||||
+-----------------------------------------------------------------+
|
||||
| The license and distribution terms for this file may be |
|
||||
| found in the file LICENSE in this distribution or at |
|
||||
| |
|
||||
| http://www.rtems.org/license/LICENSE. |
|
||||
| |
|
||||
+-----------------------------------------------------------------+
|
||||
\*===============================================================*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libi2c.h>
|
||||
|
||||
#include <libchip/spi-fram-fm25l256.h>
|
||||
#include <rtems/libio.h>
|
||||
|
||||
|
||||
static spi_memdrv_t spi_fram_fm25l256_rw_drv_t = {
|
||||
{/* public fields */
|
||||
.ops = &spi_memdrv_rw_ops, /* operations of general memdrv */
|
||||
.size = sizeof (spi_fram_fm25l256_rw_drv_t),
|
||||
},
|
||||
{ /* our private fields */
|
||||
.baudrate = 2000000,
|
||||
.erase_before_program = false,
|
||||
.empty_state = 0xff,
|
||||
.page_size = 0x8000, /* 32K programming page size in bytes */
|
||||
.sector_size = 1, /* erase sector size in bytes */
|
||||
.mem_size = 0x8000, /* 32K total capacity in bytes */
|
||||
}
|
||||
};
|
||||
|
||||
rtems_libi2c_drv_t *spi_fram_fm25l256_rw_driver_descriptor =
|
||||
&spi_fram_fm25l256_rw_drv_t.libi2c_drv_entry;
|
||||
|
||||
static spi_memdrv_t spi_fram_fm25l256_ro_drv_t = {
|
||||
{/* public fields */
|
||||
.ops = &spi_memdrv_ro_ops, /* operations of general memdrv */
|
||||
.size = sizeof (spi_fram_fm25l256_ro_drv_t),
|
||||
},
|
||||
{ /* our private fields */
|
||||
.baudrate = 2000000,
|
||||
.erase_before_program = false,
|
||||
.empty_state = 0xff,
|
||||
.page_size = 0x8000, /* 32k programming page size in bytes */
|
||||
.sector_size = 1, /* erase sector size in bytes */
|
||||
.mem_size = 0x8000, /* 32k total capacity in bytes */
|
||||
}
|
||||
};
|
||||
|
||||
rtems_libi2c_drv_t *spi_fram_fm25l256_ro_driver_descriptor =
|
||||
&spi_fram_fm25l256_ro_drv_t.libi2c_drv_entry;
|
||||
442
bsps/shared/dev/i2c/spi-memdrv.c
Normal file
442
bsps/shared/dev/i2c/spi-memdrv.c
Normal file
@@ -0,0 +1,442 @@
|
||||
/*===============================================================*\
|
||||
| Project: SPI driver for spi memory devices |
|
||||
+-----------------------------------------------------------------+
|
||||
| Copyright (c) 2008 |
|
||||
| Embedded Brains GmbH |
|
||||
| Obere Lagerstr. 30 |
|
||||
| D-82178 Puchheim |
|
||||
| Germany |
|
||||
| rtems@embedded-brains.de |
|
||||
+-----------------------------------------------------------------+
|
||||
| The license and distribution terms for this file may be |
|
||||
| found in the file LICENSE in this distribution or at |
|
||||
| |
|
||||
| http://www.rtems.org/license/LICENSE. |
|
||||
| |
|
||||
+-----------------------------------------------------------------+
|
||||
\*===============================================================*/
|
||||
/*
|
||||
* FIXME: currently, this driver only supports read/write accesses
|
||||
* erase accesses are to be completed
|
||||
*/
|
||||
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libi2c.h>
|
||||
|
||||
#include <libchip/spi-memdrv.h>
|
||||
#include <rtems/libio.h>
|
||||
|
||||
#define SPI_MEM_CMD_WREN 0x06
|
||||
#define SPI_MEM_CMD_WRDIS 0x04
|
||||
#define SPI_MEM_CMD_RDID 0x9F
|
||||
#define SPI_MEM_CMD_RDSR 0x05
|
||||
#define SPI_MEM_CMD_WRSR 0x01
|
||||
#define SPI_MEM_CMD_READ 0x03
|
||||
#define SPI_MEM_CMD_PP 0x02 /* page program */
|
||||
#define SPI_MEM_CMD_SE 0xD8 /* sector erase */
|
||||
#define SPI_MEM_CMD_BE 0xC7 /* bulk erase */
|
||||
#define SPI_MEM_CMD_DP 0xB9 /* deep power down */
|
||||
#define SPI_MEM_CMD_RES 0xAB /* release from deep power down */
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_status_code spi_memdrv_minor2param_ptr
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| translate given minor device number to param pointer |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_minor_number minor, /* minor number of device */
|
||||
spi_memdrv_param_t **param_ptr /* ptr to param ptr */
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| o = ok or error code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
spi_memdrv_t *drv_ptr;
|
||||
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = -rtems_libi2c_ioctl(minor,
|
||||
RTEMS_LIBI2C_IOCTL_GET_DRV_T,
|
||||
&drv_ptr);
|
||||
}
|
||||
if ((rc == RTEMS_SUCCESSFUL) &&
|
||||
(drv_ptr->libi2c_drv_entry.size != sizeof(spi_memdrv_t))) {
|
||||
rc = RTEMS_INVALID_SIZE;
|
||||
}
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
*param_ptr = &(drv_ptr->spi_memdrv_param);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static rtems_status_code spi_memdrv_wait_ms
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| wait a certain interval given in ms |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int ms /* time to wait in milliseconds */
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| o = ok or error code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
rtems_interval ticks_per_second;
|
||||
|
||||
ticks_per_second = rtems_clock_get_ticks_per_second();
|
||||
(void) rtems_task_wake_after(ticks_per_second * ms / 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_status_code spi_memdrv_write
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| write a block of data to flash |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_major_number major, /* major device number */
|
||||
rtems_device_minor_number minor, /* minor device number */
|
||||
void *arg /* ptr to write argument struct */
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| o = ok or error code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
rtems_libio_rw_args_t *rwargs = arg;
|
||||
off_t off = rwargs->offset;
|
||||
int cnt = rwargs->count;
|
||||
unsigned char *buf = (unsigned char *)rwargs->buffer;
|
||||
int bytes_sent = 0;
|
||||
int curr_cnt;
|
||||
unsigned char cmdbuf[4];
|
||||
int ret_cnt = 0;
|
||||
int cmd_size;
|
||||
spi_memdrv_param_t *mem_param_ptr;
|
||||
rtems_libi2c_tfr_mode_t tfr_mode = {
|
||||
.baudrate = 20000000, /* maximum bits per second */
|
||||
.bits_per_char = 8, /* how many bits per byte/word/longword? */
|
||||
.lsb_first = FALSE, /* FALSE: send MSB first */
|
||||
.clock_inv = FALSE, /* FALSE: non-inverted clock (high active) */
|
||||
.clock_phs = FALSE /* FALSE: clock starts in middle of data tfr */
|
||||
} ;
|
||||
|
||||
/*
|
||||
* get mem parameters
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = spi_memdrv_minor2param_ptr(minor,&mem_param_ptr);
|
||||
}
|
||||
/*
|
||||
* check arguments
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
if ((cnt <= 0) ||
|
||||
(cnt > mem_param_ptr->mem_size) ||
|
||||
(off > (mem_param_ptr->mem_size-cnt))) {
|
||||
rc = RTEMS_INVALID_SIZE;
|
||||
}
|
||||
else if (buf == NULL) {
|
||||
rc = RTEMS_INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
while ((rc == RTEMS_SUCCESSFUL) &&
|
||||
(cnt > bytes_sent)) {
|
||||
curr_cnt = cnt - bytes_sent;
|
||||
if ((mem_param_ptr->page_size > 0) &&
|
||||
(off / mem_param_ptr->page_size) !=
|
||||
((off+curr_cnt+1) / mem_param_ptr->page_size)) {
|
||||
curr_cnt = mem_param_ptr->page_size - (off % mem_param_ptr->page_size);
|
||||
}
|
||||
/*
|
||||
* select device, set transfer mode, address device
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_start(minor);
|
||||
}
|
||||
/*
|
||||
* set transfer mode
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
tfr_mode.baudrate = mem_param_ptr->baudrate;
|
||||
rc = -rtems_libi2c_ioctl(minor,
|
||||
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
|
||||
&tfr_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* address device
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_addr(minor,TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* send write_enable command
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
cmdbuf[0] = SPI_MEM_CMD_WREN;
|
||||
ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
|
||||
if (ret_cnt < 0) {
|
||||
rc = -ret_cnt;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* terminate transfer
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_stop(minor);
|
||||
}
|
||||
/*
|
||||
* select device, set transfer mode
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_start(minor);
|
||||
}
|
||||
|
||||
/*
|
||||
* address device
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_addr(minor,TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* set transfer mode
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = -rtems_libi2c_ioctl(minor,
|
||||
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
|
||||
&tfr_mode);
|
||||
}
|
||||
/*
|
||||
* send "page program" command and address
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
cmdbuf[0] = SPI_MEM_CMD_PP;
|
||||
if (mem_param_ptr->mem_size > 0x10000 /* 256*256 */) {
|
||||
cmdbuf[1] = (off >> 16) & 0xff;
|
||||
cmdbuf[2] = (off >> 8) & 0xff;
|
||||
cmdbuf[3] = (off >> 0) & 0xff;
|
||||
cmd_size = 4;
|
||||
}
|
||||
else if (mem_param_ptr->mem_size > 256) {
|
||||
cmdbuf[1] = (off >> 8) & 0xff;
|
||||
cmdbuf[2] = (off >> 0) & 0xff;
|
||||
cmd_size = 3;
|
||||
}
|
||||
else {
|
||||
cmdbuf[1] = (off >> 0) & 0xff;
|
||||
cmd_size = 1;
|
||||
}
|
||||
|
||||
ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,cmd_size);
|
||||
if (ret_cnt < 0) {
|
||||
rc = -ret_cnt;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* send write data
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
ret_cnt = rtems_libi2c_write_bytes(minor,buf,curr_cnt);
|
||||
if (ret_cnt < 0) {
|
||||
rc = -ret_cnt;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* terminate transfer
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_stop(minor);
|
||||
}
|
||||
/*
|
||||
* wait proper time for data to store: 5ms
|
||||
* FIXME: select proper interval or poll, until device is finished
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = spi_memdrv_wait_ms(5);
|
||||
}
|
||||
/*
|
||||
* adjust bytecount to be sent and pointers
|
||||
*/
|
||||
bytes_sent += curr_cnt;
|
||||
off += curr_cnt;
|
||||
buf += curr_cnt;
|
||||
}
|
||||
rwargs->bytes_moved = bytes_sent;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
| Function: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_status_code spi_memdrv_read
|
||||
(
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Purpose: |
|
||||
| read a block of data from flash |
|
||||
+---------------------------------------------------------------------------+
|
||||
| Input Parameters: |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
rtems_device_major_number major, /* major device number */
|
||||
rtems_device_minor_number minor, /* minor device number */
|
||||
void *arg /* ptr to read argument struct */
|
||||
)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Return Value: |
|
||||
| o = ok or error code |
|
||||
\*=========================================================================*/
|
||||
{
|
||||
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
||||
rtems_libio_rw_args_t *rwargs = arg;
|
||||
off_t off = rwargs->offset;
|
||||
int cnt = rwargs->count;
|
||||
unsigned char *buf = (unsigned char *)rwargs->buffer;
|
||||
unsigned char cmdbuf[4];
|
||||
int ret_cnt = 0;
|
||||
int cmd_size;
|
||||
spi_memdrv_param_t *mem_param_ptr;
|
||||
rtems_libi2c_tfr_mode_t tfr_mode = {
|
||||
.baudrate = 20000000, /* maximum bits per second */
|
||||
.bits_per_char = 8, /* how many bits per byte/word/longword? */
|
||||
.lsb_first = FALSE, /* FALSE: send MSB first */
|
||||
.clock_inv = FALSE, /* FALSE: non-inverted clock (high active) */
|
||||
.clock_phs = FALSE /* FALSE: clock starts in middle of data tfr */
|
||||
};
|
||||
|
||||
/*
|
||||
* get mem parameters
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = spi_memdrv_minor2param_ptr(minor,&mem_param_ptr);
|
||||
}
|
||||
/*
|
||||
* check arguments
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
if ((cnt <= 0) ||
|
||||
(cnt > mem_param_ptr->mem_size) ||
|
||||
(off > (mem_param_ptr->mem_size-cnt))) {
|
||||
rc = RTEMS_INVALID_SIZE;
|
||||
}
|
||||
else if (buf == NULL) {
|
||||
rc = RTEMS_INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* select device, set transfer mode, address device
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_start(minor);
|
||||
}
|
||||
/*
|
||||
* set transfer mode
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
tfr_mode.baudrate = mem_param_ptr->baudrate;
|
||||
rc = -rtems_libi2c_ioctl(minor,
|
||||
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
|
||||
&tfr_mode);
|
||||
}
|
||||
/*
|
||||
* address device
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_addr(minor,TRUE);
|
||||
}
|
||||
|
||||
if (off >= mem_param_ptr->mem_size) {
|
||||
/*
|
||||
* HACK: beyond size of memory array? then read status register instead
|
||||
*/
|
||||
/*
|
||||
* send read status register command
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
cmdbuf[0] = SPI_MEM_CMD_RDSR;
|
||||
ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
|
||||
if (ret_cnt < 0) {
|
||||
rc = -ret_cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* send read command and address
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
cmdbuf[0] = SPI_MEM_CMD_READ;
|
||||
if (mem_param_ptr->mem_size > 0x10000 /* 256*256 */) {
|
||||
cmdbuf[1] = (off >> 16) & 0xff;
|
||||
cmdbuf[2] = (off >> 8) & 0xff;
|
||||
cmdbuf[3] = (off >> 0) & 0xff;
|
||||
cmd_size = 4;
|
||||
}
|
||||
else if (mem_param_ptr->mem_size > 256) {
|
||||
cmdbuf[1] = (off >> 8) & 0xff;
|
||||
cmdbuf[2] = (off >> 0) & 0xff;
|
||||
cmd_size = 3;
|
||||
}
|
||||
else {
|
||||
cmdbuf[1] = (off >> 0) & 0xff;
|
||||
cmd_size = 1;
|
||||
}
|
||||
ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,cmd_size);
|
||||
if (ret_cnt < 0) {
|
||||
rc = -ret_cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* fetch read data
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
ret_cnt = rtems_libi2c_read_bytes (minor,buf,cnt);
|
||||
if (ret_cnt < 0) {
|
||||
rc = -ret_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* terminate transfer
|
||||
*/
|
||||
if (rc == RTEMS_SUCCESSFUL) {
|
||||
rc = rtems_libi2c_send_stop(minor);
|
||||
}
|
||||
rwargs->bytes_moved = (rc == RTEMS_SUCCESSFUL) ? ret_cnt : 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* driver operation tables
|
||||
*/
|
||||
rtems_driver_address_table spi_memdrv_rw_ops = {
|
||||
.read_entry = spi_memdrv_read,
|
||||
.write_entry = spi_memdrv_write
|
||||
};
|
||||
|
||||
rtems_driver_address_table spi_memdrv_ro_ops = {
|
||||
.read_entry = spi_memdrv_read,
|
||||
};
|
||||
|
||||
1322
bsps/shared/dev/i2c/spi-sd-card.c
Normal file
1322
bsps/shared/dev/i2c/spi-sd-card.c
Normal file
File diff suppressed because it is too large
Load Diff
1360
bsps/shared/dev/ide/ata.c
Normal file
1360
bsps/shared/dev/ide/ata.c
Normal file
File diff suppressed because it is too large
Load Diff
215
bsps/shared/dev/ide/ata_util.c
Normal file
215
bsps/shared/dev/ide/ata_util.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2010 embedded brains GmbH.
|
||||
*
|
||||
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
|
||||
* Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libchip/ide_ctrl_io.h>
|
||||
#include <libchip/ide_ctrl_cfg.h>
|
||||
#include <libchip/ata_internal.h>
|
||||
|
||||
/* ata_process_request_on_init_phase --
|
||||
* Process the ATA request during system initialization. Request
|
||||
* processing is syncronous and doesn't use multiprocessing enviroment.
|
||||
*
|
||||
* PARAMETERS:
|
||||
* ctrl_minor - controller identifier
|
||||
* areq - ATA request
|
||||
*
|
||||
* RETURNS:
|
||||
* NONE
|
||||
*/
|
||||
void
|
||||
ata_process_request_on_init_phase(rtems_device_minor_number ctrl_minor,
|
||||
ata_req_t *areq)
|
||||
{
|
||||
uint16_t byte;/* emphasize that only 8 low bits is meaningful */
|
||||
uint8_t i;
|
||||
#if 0
|
||||
uint8_t dev;
|
||||
#endif
|
||||
uint16_t val, val1;
|
||||
volatile unsigned retries;
|
||||
|
||||
assert(areq);
|
||||
|
||||
#if 0
|
||||
dev = areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
|
||||
IDE_REGISTER_DEVICE_HEAD_DEV;
|
||||
#endif
|
||||
|
||||
ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,
|
||||
areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
|
||||
|
||||
retries = 0;
|
||||
do {
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
||||
/* If device (on INIT, i.e. it should be idle) is neither
|
||||
* busy nor ready something's fishy, i.e., there is probably
|
||||
* no device present.
|
||||
* I'd like to do a proper timeout but don't know of a portable
|
||||
* timeout routine (w/o using multitasking / rtems_task_wake_after())
|
||||
*/
|
||||
if ( ! (byte & (IDE_REGISTER_STATUS_BSY | IDE_REGISTER_STATUS_DRDY))) {
|
||||
retries++;
|
||||
if ( 10000 == retries ) {
|
||||
/* probably no drive connected */
|
||||
areq->breq->status = RTEMS_UNSATISFIED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while ((byte & IDE_REGISTER_STATUS_BSY) ||
|
||||
(!(byte & IDE_REGISTER_STATUS_DRDY)));
|
||||
|
||||
for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
|
||||
{
|
||||
uint32_t reg = (1 << i);
|
||||
if (areq->regs.to_write & reg)
|
||||
ide_controller_write_register(ctrl_minor, i,
|
||||
areq->regs.regs[i]);
|
||||
}
|
||||
|
||||
do {
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
||||
} while (byte & IDE_REGISTER_STATUS_BSY);
|
||||
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1);
|
||||
|
||||
if (val & IDE_REGISTER_STATUS_ERR)
|
||||
{
|
||||
areq->breq->status = RTEMS_IO_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(areq->type)
|
||||
{
|
||||
case ATA_COMMAND_TYPE_PIO_IN:
|
||||
if (areq->cnt)
|
||||
{
|
||||
int ccbuf = areq->cbuf;
|
||||
ide_controller_read_data_block(ctrl_minor,
|
||||
areq->breq->bufs[0].length * areq->cnt,
|
||||
areq->breq->bufs, &areq->cbuf,
|
||||
&areq->pos);
|
||||
ccbuf = areq->cbuf - ccbuf;
|
||||
areq->cnt -= ccbuf;
|
||||
}
|
||||
if (areq->cnt == 0)
|
||||
{
|
||||
areq->breq->status = RTEMS_SUCCESSFUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* this shouldn't happend on the initialization
|
||||
* phase!
|
||||
*/
|
||||
rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case ATA_COMMAND_TYPE_NON_DATA:
|
||||
areq->breq->status = RTEMS_SUCCESSFUL;
|
||||
areq->info = val1;
|
||||
break;
|
||||
|
||||
default:
|
||||
areq->breq->status = RTEMS_IO_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ata_breq_init(blkdev_request1 *breq, uint16_t *sector_buffer)
|
||||
{
|
||||
memset(breq, 0, sizeof(*breq));
|
||||
|
||||
breq->req.done_arg = breq;
|
||||
breq->req.bufnum = 1;
|
||||
breq->req.bufs [0].length = ATA_SECTOR_SIZE;
|
||||
breq->req.bufs [0].buffer = sector_buffer;
|
||||
}
|
||||
|
||||
rtems_status_code ata_identify_device(
|
||||
rtems_device_minor_number ctrl_minor,
|
||||
int dev,
|
||||
uint16_t *sector_buffer,
|
||||
ata_dev_t *device_entry
|
||||
)
|
||||
{
|
||||
ata_req_t areq;
|
||||
blkdev_request1 breq;
|
||||
|
||||
ata_breq_init(&breq, sector_buffer);
|
||||
|
||||
/*
|
||||
* Issue DEVICE IDENTIFY ATA command and get device
|
||||
* configuration
|
||||
*/
|
||||
memset(&areq, 0, sizeof(ata_req_t));
|
||||
areq.type = ATA_COMMAND_TYPE_PIO_IN;
|
||||
areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
|
||||
areq.regs.regs [IDE_REGISTER_COMMAND] = ATA_COMMAND_IDENTIFY_DEVICE;
|
||||
areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
|
||||
areq.breq = (rtems_blkdev_request *)&breq;
|
||||
areq.cnt = breq.req.bufnum;
|
||||
areq.regs.regs [IDE_REGISTER_DEVICE_HEAD] |=
|
||||
dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS;
|
||||
|
||||
/*
|
||||
* Process the request. Special processing of requests on
|
||||
* initialization phase is needed because at this moment there
|
||||
* is no multitasking enviroment
|
||||
*/
|
||||
ata_process_request_on_init_phase(ctrl_minor, &areq);
|
||||
|
||||
/* check status of I/O operation */
|
||||
if (breq.req.status != RTEMS_SUCCESSFUL) {
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse returned device configuration and fill in ATA internal
|
||||
* device info structure
|
||||
*/
|
||||
device_entry->cylinders =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]);
|
||||
device_entry->heads =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]);
|
||||
device_entry->sectors =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]);
|
||||
device_entry->lba_sectors =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]);
|
||||
device_entry->lba_sectors <<= 16;
|
||||
device_entry->lba_sectors += CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]);
|
||||
device_entry->lba_avaible =
|
||||
(CF_LE_W(sector_buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1;
|
||||
|
||||
if ((CF_LE_W(sector_buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) &
|
||||
ATA_IDENT_BIT_VALID) == 0) {
|
||||
/* no "supported modes" info -> use default */
|
||||
device_entry->mode_active = ATA_MODES_PIO3;
|
||||
} else {
|
||||
device_entry->modes_available =
|
||||
((CF_LE_W(sector_buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) |
|
||||
((CF_LE_W(sector_buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x2) ?
|
||||
ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x4) ?
|
||||
ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0);
|
||||
if (device_entry->modes_available == 0) {
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
200
bsps/shared/dev/ide/ide_controller.c
Normal file
200
bsps/shared/dev/ide/ide_controller.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* ide_controller.c
|
||||
*
|
||||
* This is generic rtems driver for IDE controllers.
|
||||
*
|
||||
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
|
||||
* Authors: Alexandra Kossovsky <sasha@oktet.ru>
|
||||
* Eugeny S. Mints <Eugeny.Mints@oktet.ru>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define IDE_CONTROLLER_TRACE 0
|
||||
|
||||
#include <rtems/chain.h>
|
||||
#include <errno.h>
|
||||
#include <rtems/blkdev.h>
|
||||
|
||||
#include <libchip/ide_ctrl.h>
|
||||
#include <libchip/ide_ctrl_cfg.h>
|
||||
#include <libchip/ide_ctrl_io.h>
|
||||
|
||||
#if IDE_CONTROLLER_TRACE
|
||||
int ide_controller_trace = 1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ide_controller_initialize --
|
||||
* Initializes all configured IDE controllers. Controllers configuration
|
||||
* table is provided by BSP
|
||||
*
|
||||
* PARAMETERS:
|
||||
* major - device major number
|
||||
* minor_arg - device minor number
|
||||
* args - arguments
|
||||
*
|
||||
* RETURNS:
|
||||
* RTEMS_SUCCESSFUL on success, or error code if
|
||||
* error occured
|
||||
*/
|
||||
rtems_device_driver
|
||||
ide_controller_initialize(rtems_device_major_number major,
|
||||
rtems_device_minor_number minor_arg,
|
||||
void *args)
|
||||
{
|
||||
unsigned long minor;
|
||||
|
||||
/* FIXME: may be it should be done on compilation phase */
|
||||
if (IDE_Controller_Count > IDE_CTRL_MAX_MINOR_NUMBER)
|
||||
rtems_fatal_error_occurred(RTEMS_TOO_MANY);
|
||||
|
||||
for (minor=0; minor < IDE_Controller_Count; minor++)
|
||||
{
|
||||
IDE_Controller_Table[minor].status = IDE_CTRL_NON_INITIALIZED;
|
||||
|
||||
if ((IDE_Controller_Table[minor].probe == NULL ||
|
||||
IDE_Controller_Table[minor].probe(minor)) &&
|
||||
(IDE_Controller_Table[minor].fns->ctrl_probe == NULL ||
|
||||
IDE_Controller_Table[minor].fns->ctrl_probe(minor)))
|
||||
{
|
||||
dev_t dev;
|
||||
dev = rtems_filesystem_make_dev_t( major, minor );
|
||||
if (mknod(IDE_Controller_Table[minor].name,
|
||||
0777 | S_IFBLK, dev ) < 0)
|
||||
rtems_fatal_error_occurred(errno);
|
||||
IDE_Controller_Table[minor].fns->ctrl_initialize(minor);
|
||||
IDE_Controller_Table[minor].status = IDE_CTRL_INITIALIZED;
|
||||
}
|
||||
}
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ide_controller_read_data_block --
|
||||
* Read data block via controller's data register
|
||||
*
|
||||
* PARAMETERS:
|
||||
* minor - minor number of controller
|
||||
* block_size - number of bytes to read
|
||||
* bufs - set of buffers to store data
|
||||
* cbuf - number of current buffer from the set
|
||||
* pos - position inside current buffer 'cbuf'
|
||||
*
|
||||
* RETURNS:
|
||||
* NONE
|
||||
*/
|
||||
void
|
||||
ide_controller_read_data_block(rtems_device_minor_number minor,
|
||||
uint32_t block_size,
|
||||
rtems_blkdev_sg_buffer *bufs,
|
||||
uint32_t *cbuf,
|
||||
uint32_t *pos)
|
||||
{
|
||||
#if IDE_CONTROLLER_TRACE
|
||||
if (ide_controller_trace)
|
||||
printk ("IDE data block read: %d:%d\n", *cbuf, bufs[*cbuf].block);
|
||||
#endif
|
||||
IDE_Controller_Table[minor].fns->ctrl_read_block(minor, block_size, bufs,
|
||||
cbuf, pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* ide_controller_write_data_block --
|
||||
* Write data block via controller's data register
|
||||
*
|
||||
* PARAMETERS:
|
||||
* minor - minor number of controller
|
||||
* block_size - number of bytes to write
|
||||
* bufs - set of buffers which store data
|
||||
* cbuf - number of current buffer from the set
|
||||
* pos - position inside current buffer 'cbuf'
|
||||
*
|
||||
* RETURNS:
|
||||
* NONE
|
||||
*/
|
||||
void
|
||||
ide_controller_write_data_block(rtems_device_minor_number minor,
|
||||
uint32_t block_size,
|
||||
rtems_blkdev_sg_buffer *bufs,
|
||||
uint32_t *cbuf,
|
||||
uint32_t *pos)
|
||||
|
||||
{
|
||||
#if IDE_CONTROLLER_TRACE
|
||||
if (ide_controller_trace)
|
||||
printk ("IDE data block write: %d:%d\n", *cbuf, bufs[*cbuf].block);
|
||||
#endif
|
||||
IDE_Controller_Table[minor].fns->ctrl_write_block(minor, block_size, bufs,
|
||||
cbuf, pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* ide_controller_read_register --
|
||||
* Read controller's register
|
||||
*
|
||||
* PARAMETERS:
|
||||
* minor - minor number of controller
|
||||
* reg - register to read
|
||||
* value - placeholder for result
|
||||
*
|
||||
* RETURNS
|
||||
* NONE
|
||||
*/
|
||||
void
|
||||
ide_controller_read_register(rtems_device_minor_number minor,
|
||||
int reg,
|
||||
uint16_t *value)
|
||||
{
|
||||
IDE_Controller_Table[minor].fns->ctrl_reg_read(minor, reg, value);
|
||||
#if IDE_CONTROLLER_TRACE
|
||||
if (ide_controller_trace)
|
||||
printk ("IDE read reg: %d => %04x\n", reg, *value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* ide_controller_write_register --
|
||||
* Write controller's register
|
||||
*
|
||||
* PARAMETERS:
|
||||
* minor - minor number of controller
|
||||
* reg - register to write
|
||||
* value - value to write
|
||||
*
|
||||
* RETURNS:
|
||||
* NONE
|
||||
*/
|
||||
void
|
||||
ide_controller_write_register(rtems_device_minor_number minor, int reg,
|
||||
uint16_t value)
|
||||
{
|
||||
#if IDE_CONTROLLER_TRACE
|
||||
if (ide_controller_trace)
|
||||
printk ("IDE write reg: %d => %04x\n", reg, value);
|
||||
#endif
|
||||
IDE_Controller_Table[minor].fns->ctrl_reg_write(minor, reg, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* ide_controller_config_io_speed --
|
||||
* Set controller's speed of IO operations
|
||||
*
|
||||
* PARAMETERS:
|
||||
* minor - minor number of controller
|
||||
* modes_available - speeds available
|
||||
*
|
||||
* RETURNS:
|
||||
* RTEMS_SUCCESSFUL on success, or error code if
|
||||
* error occured
|
||||
*/
|
||||
rtems_status_code
|
||||
ide_controller_config_io_speed(int minor, uint16_t modes_available)
|
||||
{
|
||||
return IDE_Controller_Table[minor].fns->ctrl_config_io_speed(
|
||||
minor,
|
||||
modes_available);
|
||||
}
|
||||
3
bsps/shared/dev/rtc/README.ds1643
Normal file
3
bsps/shared/dev/rtc/README.ds1643
Normal file
@@ -0,0 +1,3 @@
|
||||
The Mostek M48T08 is compatible with the Dallas Semiconductor DS1643. Please
|
||||
use that driver.
|
||||
|
||||
48
bsps/shared/dev/rtc/README.icm7170
Normal file
48
bsps/shared/dev/rtc/README.icm7170
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
Configuration Table Use
|
||||
=======================
|
||||
|
||||
sDeviceName
|
||||
|
||||
The name of this device.
|
||||
|
||||
deviceType
|
||||
|
||||
This field must be RTC_ICM7170.
|
||||
|
||||
pDeviceFns
|
||||
|
||||
The device interface control table. This must be icm7170_fns.
|
||||
|
||||
deviceProbe
|
||||
|
||||
This is the address of the routine which probes to see if the device
|
||||
is present.
|
||||
|
||||
pDeviceParams
|
||||
|
||||
This field specifies the clock frequency. It may be one of the
|
||||
following:
|
||||
ICM7170_AT_32_KHZ
|
||||
ICM7170_AT_1_MHZ
|
||||
ICM7170_AT_2_MHZ
|
||||
ICM7170_AT_4_MHZ
|
||||
|
||||
ulCtrlPort1
|
||||
|
||||
This field is the base address of the RTC area of the chip.
|
||||
|
||||
ulCtrlPort2
|
||||
|
||||
This field is ignored.
|
||||
|
||||
ulDataPort
|
||||
|
||||
This field is ignored.
|
||||
|
||||
|
||||
getRegister
|
||||
setRegister
|
||||
|
||||
These follow standard conventions.
|
||||
|
||||
44
bsps/shared/dev/rtc/README.m48t08
Normal file
44
bsps/shared/dev/rtc/README.m48t08
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
Configuration Table Use
|
||||
=======================
|
||||
|
||||
sDeviceName
|
||||
|
||||
The name of this device.
|
||||
|
||||
deviceType
|
||||
|
||||
This field must be RTC_M48T08.
|
||||
|
||||
pDeviceFns
|
||||
|
||||
The device interface control table. This must be m48t08_fns.
|
||||
|
||||
deviceProbe
|
||||
|
||||
This is the address of the routine which probes to see if the device
|
||||
is present.
|
||||
|
||||
pDeviceParams
|
||||
|
||||
This is ignored and should be NULL.
|
||||
|
||||
ulCtrlPort1
|
||||
|
||||
This field is the base address of the RTC area of the chip. The
|
||||
NVRAM portion of the chip is ignored.
|
||||
|
||||
ulCtrlPort2
|
||||
|
||||
This field is ignored.
|
||||
|
||||
ulDataPort
|
||||
|
||||
This field is ignored.
|
||||
|
||||
|
||||
getRegister
|
||||
setRegister
|
||||
|
||||
These follow standard conventions.
|
||||
|
||||
1
bsps/shared/dev/rtc/README.m48t18
Normal file
1
bsps/shared/dev/rtc/README.m48t18
Normal file
@@ -0,0 +1 @@
|
||||
This is supported by the m48t08 driver.
|
||||
1
bsps/shared/dev/rtc/README.mc146818a
Normal file
1
bsps/shared/dev/rtc/README.mc146818a
Normal file
@@ -0,0 +1 @@
|
||||
This is supported by the mc146818a driver.
|
||||
33
bsps/shared/dev/rtc/STATUS
Normal file
33
bsps/shared/dev/rtc/STATUS
Normal file
@@ -0,0 +1,33 @@
|
||||
General
|
||||
=======
|
||||
|
||||
+ It would be nice to utilize the interrupt capabilities of some
|
||||
RTC parts. This could be used to trigger checking the software
|
||||
clock against the hardware clock.
|
||||
|
||||
+ The periodic capability of most RTCs is not suitable for use
|
||||
as a general purpose flexible clock tick source. For example,
|
||||
many RTCs generate only a handful of periods with 100 Hz being the
|
||||
most frequent.
|
||||
|
||||
+ The tick field is not set on get. Anything smaller than a second
|
||||
is ignored on set and get operations.
|
||||
|
||||
+ Day of week is ignored since RTEMS does not set it internally.
|
||||
|
||||
+ There is no attempt in RTEMS to know about time zones.
|
||||
|
||||
Harris ICM7170
|
||||
==============
|
||||
|
||||
+ Tested on a DMV177.
|
||||
|
||||
+ Interrupt capabilities are ignored.
|
||||
|
||||
Mostek 48T08
|
||||
============
|
||||
|
||||
+ Untested.
|
||||
|
||||
+ NVRAM is ignored.
|
||||
|
||||
461
bsps/shared/dev/rtc/ds1375.c
Normal file
461
bsps/shared/dev/rtc/ds1375.c
Normal file
@@ -0,0 +1,461 @@
|
||||
/* Driver for the Maxim 1375 i2c RTC (TOD only; very simple...) */
|
||||
|
||||
/*
|
||||
* Authorship
|
||||
* ----------
|
||||
* This software was created by
|
||||
*
|
||||
* Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
|
||||
* Stanford Linear Accelerator Center, Stanford University.
|
||||
*
|
||||
* Acknowledgement of sponsorship
|
||||
* ------------------------------
|
||||
* The software was produced by
|
||||
* the Stanford Linear Accelerator Center, Stanford University,
|
||||
* under Contract DE-AC03-76SFO0515 with the Department of Energy.
|
||||
*
|
||||
* Government disclaimer of liability
|
||||
* ----------------------------------
|
||||
* Neither the United States nor the United States Department of Energy,
|
||||
* nor any of their employees, makes any warranty, express or implied, or
|
||||
* assumes any legal liability or responsibility for the accuracy,
|
||||
* completeness, or usefulness of any data, apparatus, product, or process
|
||||
* disclosed, or represents that its use would not infringe privately owned
|
||||
* rights.
|
||||
*
|
||||
* Stanford disclaimer of liability
|
||||
* --------------------------------
|
||||
* Stanford University makes no representations or warranties, express or
|
||||
* implied, nor assumes any liability for the use of this software.
|
||||
*
|
||||
* Stanford disclaimer of copyright
|
||||
* --------------------------------
|
||||
* Stanford University, owner of the copyright, hereby disclaims its
|
||||
* copyright and all other rights in this software. Hence, anyone may
|
||||
* freely use it for any purpose without restriction.
|
||||
*
|
||||
* Maintenance of notices
|
||||
* ----------------------
|
||||
* In the interest of clarity regarding the origin and status of this
|
||||
* SLAC software, this and all the preceding Stanford University notices
|
||||
* are to remain affixed to any copy or derivative of this software made
|
||||
* or distributed by the recipient and are to be affixed to any copy of
|
||||
* software made or distributed by the recipient that contains a copy or
|
||||
* derivative of this software.
|
||||
*
|
||||
* ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
|
||||
*/
|
||||
|
||||
/* This driver uses the file-system interface to the i2c bus */
|
||||
|
||||
#include <unistd.h> /* write, read, close */
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/rtc.h>
|
||||
#include <rtems/score/sysstate.h>
|
||||
#include <libchip/rtc.h>
|
||||
#include <libchip/ds1375-rtc.h>
|
||||
|
||||
#include <sys/fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
#define STATIC static
|
||||
#undef DEBUG
|
||||
|
||||
/* The RTC driver routines are possibly called during
|
||||
* system initialization -- that would be prior to opening
|
||||
* the console. At this point it is not safe to use stdio
|
||||
* (printf, perror etc.).
|
||||
* Our file descriptors may even be 0..2
|
||||
*/
|
||||
#define STDIOSAFE(fmt,args...) \
|
||||
do { \
|
||||
if ( _System_state_Is_up( _System_state_Get() ) ) { \
|
||||
fprintf(stderr,fmt,args); \
|
||||
} else { \
|
||||
printk(fmt,args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
STATIC uint8_t ds1375_bcd2bin(uint8_t x)
|
||||
{
|
||||
uint8_t h = x & 0xf0;
|
||||
|
||||
/* 8*hi + 2*hi + lo */
|
||||
return ( h >> 1 ) + ( h >> 3 ) + ( x & 0xf );
|
||||
}
|
||||
|
||||
STATIC uint8_t ds1375_bin2bcd(uint8_t x)
|
||||
{
|
||||
uint8_t h = x/10;
|
||||
|
||||
return ( h << 4 ) + ( x - ( ( h << 3 ) + ( h << 1 ) ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Register Definitions and Access Macros
|
||||
*
|
||||
* The xxx_REG macros are offsets into the register files
|
||||
* The xxx_OFF macros are offsets into a in-memory buffer
|
||||
* starting at the seconds (for the 1375 both,
|
||||
* _REG and _OFF happen to be identical).
|
||||
*/
|
||||
#define DS1375_SEC_REG 0x0
|
||||
#define DS1375_SEC_OFF (DS1375_SEC_REG-DS1375_SEC_REG)
|
||||
/* Extract seconds and convert to binary */
|
||||
#define DS1375_SEC(x) ds1375_bcd2bin( ((x)[DS1375_SEC_OFF]) & 0x7f )
|
||||
|
||||
#define DS1375_MIN_REG 0x1
|
||||
#define DS1375_MIN_OFF (DS1375_MIN_REG-DS1375_SEC_REG)
|
||||
/* Extract minutes and convert to binary */
|
||||
#define DS1375_MIN(x) ds1375_bcd2bin( ((x)[DS1375_MIN_OFF]) & 0x7f )
|
||||
|
||||
#define DS1375_HR_REG 0x2
|
||||
#define DS1375_HR_OFF (DS1375_HR_REG-DS1375_SEC_REG)
|
||||
#define DS1375_HR_1224 (1<<6)
|
||||
#define DS1375_HR_AMPM (1<<5)
|
||||
/* Are hours in AM/PM representation ? */
|
||||
#define DS1375_IS_AMPM(x) (DS1375_HR_1224 & ((x)[DS1375_HR_OFF]))
|
||||
/* Are we PM ? */
|
||||
#define DS1375_IS_PM(x) (DS1375_HR_AMPM & ((x)[DS1375_HR_OFF]))
|
||||
/* Extract hours (12h mode) and convert to binary */
|
||||
#define DS1375_HR_12(x) ds1375_bcd2bin( ((x)[DS1375_HR_OFF]) & 0x1f )
|
||||
/* Extract hours (24h mode) and convert to binary */
|
||||
#define DS1375_HR_24(x) ds1375_bcd2bin( ((x)[DS1375_HR_OFF]) & 0x3f )
|
||||
|
||||
#define DS1375_DAY_REG 0x3
|
||||
#define DS1375_DAY_OFF (DS1375_DAY_REG-DS1375_SEC_REG)
|
||||
#define DS1375_DAT_REG 0x4
|
||||
#define DS1375_DAT_OFF (DS1375_DAT_REG-DS1375_SEC_REG)
|
||||
/* Extract date and convert to binary */
|
||||
#define DS1375_DAT(x) ds1375_bcd2bin( ((x)[DS1375_DAT_OFF]) & 0x3f )
|
||||
#define DS1375_MON_REG 0x5
|
||||
#define DS1375_MON_OFF (DS1375_MON_REG-DS1375_SEC_REG)
|
||||
#define DS1375_MON_CTRY (1<<7)
|
||||
/* Is century bit set ? */
|
||||
#define DS1375_IS_CTRY(x) (((x)[DS1375_MON_OFF]) & DS1375_MON_CTRY)
|
||||
/* Extract month and convert to binary */
|
||||
#define DS1375_MON(x) ds1375_bcd2bin( ((x)[DS1375_MON_OFF]) & 0x1f )
|
||||
|
||||
#define DS1375_YR_REG 0x6
|
||||
#define DS1375_YR_OFF (DS1375_YR_REG-DS1375_SEC_REG)
|
||||
/* Extract year and convert to binary */
|
||||
#define DS1375_YR(x) ds1375_bcd2bin( ((x)[DS1375_YR_OFF]) & 0xff )
|
||||
|
||||
/* CR Register and bit definitions */
|
||||
#define DS1375_CR_REG 0xe
|
||||
#define DS1375_CR_ECLK (1<<7)
|
||||
#define DS1375_CR_CLKSEL1 (1<<6)
|
||||
#define DS1375_CR_CLKSEL0 (1<<5)
|
||||
#define DS1375_CR_RS2 (1<<4)
|
||||
#define DS1375_CR_RS1 (1<<3)
|
||||
#define DS1375_CR_INTCN (1<<2)
|
||||
#define DS1375_CR_A2IE (1<<1)
|
||||
#define DS1375_CR_A1IE (1<<0)
|
||||
|
||||
#define DS1375_CSR_REG 0xf
|
||||
|
||||
/* User SRAM (8 bytes) */
|
||||
#define DS1375_RAM 0x10 /* start of 8 bytes user ram */
|
||||
|
||||
/* Access Primitives */
|
||||
|
||||
STATIC int rd_bytes(
|
||||
int fd,
|
||||
uint32_t off,
|
||||
uint8_t *buf,
|
||||
int len
|
||||
)
|
||||
{
|
||||
uint8_t ptr = off;
|
||||
|
||||
return 1 == write( fd, &ptr, 1 ) && len == read( fd, buf, len ) ? 0 : -1;
|
||||
}
|
||||
|
||||
STATIC int wr_bytes(
|
||||
int fd,
|
||||
uint32_t off,
|
||||
uint8_t *buf,
|
||||
int len
|
||||
)
|
||||
{
|
||||
uint8_t d[ len + 1 ];
|
||||
|
||||
/* Must not break up writing of the register pointer and
|
||||
* the data to-be-written into multiple write() calls
|
||||
* because every 'write()' operation sends START and
|
||||
* the chip interprets the first byte after START as
|
||||
* the register pointer.
|
||||
*/
|
||||
|
||||
d[0] = off;
|
||||
memcpy( d + 1, buf, len );
|
||||
|
||||
return len + 1 == write( fd, d, len + 1 ) ? 0 : -1;
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
|
||||
static int getfd(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
return open( (const char *)RTC_Table[minor].ulCtrlPort1, O_RDWR );
|
||||
}
|
||||
|
||||
/* Driver Access Functions */
|
||||
|
||||
STATIC void ds1375_initialize(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
int fd;
|
||||
uint8_t cr;
|
||||
|
||||
if ( ( fd = getfd( minor ) ) >= 0 ) {
|
||||
if ( 0 == rd_bytes( fd, DS1375_CR_REG, &cr, 1 ) ) {
|
||||
/* make sure clock is enabled */
|
||||
if ( ! ( DS1375_CR_ECLK & cr ) ) {
|
||||
cr |= DS1375_CR_ECLK;
|
||||
wr_bytes( fd, DS1375_CR_REG, &cr, 1 );
|
||||
}
|
||||
}
|
||||
close( fd );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
STATIC int ds1375_get_time(
|
||||
int minor,
|
||||
rtems_time_of_day *time
|
||||
)
|
||||
{
|
||||
int rval = -1;
|
||||
int fd;
|
||||
uint8_t buf[DS1375_YR_REG + 1 - DS1375_SEC_REG];
|
||||
|
||||
if ( time && ( ( fd = getfd( minor ) ) >= 0 ) ) {
|
||||
if ( 0 == rd_bytes( fd, DS1375_SEC_REG, buf, sizeof(buf) ) ) {
|
||||
time->year = DS1375_IS_CTRY( buf ) ? 2000 : 1900;
|
||||
time->year += DS1375_YR ( buf );
|
||||
time->month = DS1375_MON( buf );
|
||||
time->day = DS1375_DAT( buf ); /* DAY is weekday */
|
||||
|
||||
if ( DS1375_IS_AMPM( buf ) ) {
|
||||
time->hour = DS1375_HR_12 ( buf );
|
||||
if ( DS1375_IS_PM( buf ) )
|
||||
time->hour += 12;
|
||||
} else {
|
||||
time->hour = DS1375_HR_24 ( buf );
|
||||
}
|
||||
|
||||
time->minute = DS1375_MIN( buf );
|
||||
time->second = DS1375_SEC( buf );
|
||||
time->ticks = 0;
|
||||
rval = 0;
|
||||
}
|
||||
close( fd );
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
STATIC int ds1375_set_time(
|
||||
int minor,
|
||||
const rtems_time_of_day *time
|
||||
)
|
||||
{
|
||||
int rval = -1;
|
||||
int fd = -1;
|
||||
time_t secs;
|
||||
struct tm tm;
|
||||
uint8_t buf[DS1375_YR_REG + 1 - DS1375_SEC_REG];
|
||||
uint8_t cr = 0xff;
|
||||
|
||||
/*
|
||||
* The clock hardware maintains the day-of-week as a separate counter
|
||||
* so we must compute it ourselves (rtems_time_of_day doesn't come
|
||||
* with a day of week).
|
||||
*/
|
||||
secs = _TOD_To_seconds( time );
|
||||
/* we're only interested in tm_wday... */
|
||||
gmtime_r( &secs, &tm );
|
||||
|
||||
buf[DS1375_SEC_OFF] = ds1375_bin2bcd( time->second );
|
||||
buf[DS1375_MIN_OFF] = ds1375_bin2bcd( time->minute );
|
||||
/* bin2bcd(hour) implicitly selects 24h mode since ms-bit is clear */
|
||||
buf[DS1375_HR_OFF] = ds1375_bin2bcd( time->hour );
|
||||
buf[DS1375_DAY_OFF] = tm.tm_wday + 1;
|
||||
buf[DS1375_DAT_OFF] = ds1375_bin2bcd( time->day );
|
||||
buf[DS1375_MON_OFF] = ds1375_bin2bcd( time->month );
|
||||
|
||||
if ( time->year >= 2000 ) {
|
||||
buf[DS1375_YR_OFF] = ds1375_bin2bcd( time->year - 2000 );
|
||||
buf[DS1375_MON_OFF] |= DS1375_MON_CTRY;
|
||||
} else {
|
||||
buf[DS1375_YR_OFF] = ds1375_bin2bcd( time->year - 1900 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop clock; update registers and restart. This is slightly
|
||||
* slower than just writing everyting but if we did that we
|
||||
* could get inconsistent registers if this routine would not
|
||||
* complete in less than 1s (says the datasheet) and we don't
|
||||
* know if we are going to be pre-empted for some time...
|
||||
*/
|
||||
if ( ( fd = getfd( minor ) ) < 0 ) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ( rd_bytes( fd, DS1375_CR_REG, &cr, 1 ) )
|
||||
goto cleanup;
|
||||
|
||||
cr &= ~DS1375_CR_ECLK;
|
||||
|
||||
/* This stops the clock */
|
||||
if ( wr_bytes( fd, DS1375_CR_REG, &cr, 1 ) )
|
||||
goto cleanup;
|
||||
|
||||
/* write new contents */
|
||||
if ( wr_bytes( fd, DS1375_SEC_REG, buf, sizeof(buf) ) )
|
||||
goto cleanup;
|
||||
|
||||
rval = 0;
|
||||
|
||||
cleanup:
|
||||
if ( fd >= 0 ) {
|
||||
if ( ! ( DS1375_CR_ECLK & cr ) ) {
|
||||
/* start clock; this handles some cases of failure
|
||||
* after stopping the clock by restarting it again
|
||||
*/
|
||||
cr |= DS1375_CR_ECLK;
|
||||
if ( wr_bytes( fd, DS1375_CR_REG, &cr, 1 ) )
|
||||
rval = -1;
|
||||
}
|
||||
close( fd );
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Debugging / Testing */
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* Don't forget to set "TZ" when using these test routines */
|
||||
|
||||
/* What is rtems_time_of_day good for ? Why not use std types ? */
|
||||
|
||||
uint32_t
|
||||
ds1375_get_time_tst()
|
||||
{
|
||||
rtems_time_of_day rtod;
|
||||
time_t secs;
|
||||
|
||||
ds1375_get_time( 0, &rtod );
|
||||
secs = _TOD_To_seconds( &rtod );
|
||||
printf( "%s\n", ctime( &secs ) );
|
||||
return secs;
|
||||
}
|
||||
|
||||
int
|
||||
ds1375_set_time_tst( const char *datstr, rtems_time_of_day *prt )
|
||||
{
|
||||
struct tm tm;
|
||||
time_t secs;
|
||||
rtems_time_of_day rt;
|
||||
|
||||
if ( !datstr )
|
||||
return -1;
|
||||
|
||||
if ( ! strptime( datstr, "%Y-%m-%d/%T", &tm ) )
|
||||
return -2;
|
||||
|
||||
if ( ! prt )
|
||||
prt = &rt;
|
||||
|
||||
secs = mktime( &tm );
|
||||
|
||||
/* convert to UTC */
|
||||
gmtime_r( &secs, &tm );
|
||||
|
||||
printf("Y: %"PRIu32" ", (prt->year = tm.tm_year + 1900) );
|
||||
printf("M: %"PRIu32" ", (prt->month = tm.tm_mon + 1) );
|
||||
printf("D: %"PRIu32" ", (prt->day = tm.tm_mday ) );
|
||||
printf("h: %"PRIu32" ", (prt->hour = tm.tm_hour ) );
|
||||
printf("m: %"PRIu32" ", (prt->minute = tm.tm_min ) );
|
||||
printf("s: %"PRIu32"\n", (prt->second = tm.tm_sec ) );
|
||||
prt->ticks = 0;
|
||||
|
||||
return ( prt == &rt ) ? ds1375_set_time( 0, &rt ) : 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
uint32_t
|
||||
rtc_ds1375_get_register( uintptr_t port, uint8_t reg )
|
||||
{
|
||||
int fd;
|
||||
uint8_t v;
|
||||
uint32_t rval = -1;
|
||||
|
||||
if ( ( fd = open( (const char*)port, O_RDWR ) ) >= 0 ) {
|
||||
|
||||
if ( 0 == rd_bytes( fd, reg, &v, 1 ) ) {
|
||||
rval = v;
|
||||
}
|
||||
close( fd );
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
void
|
||||
rtc_ds1375_set_register( uintptr_t port, uint8_t reg, uint32_t value )
|
||||
{
|
||||
int fd;
|
||||
uint8_t v = value;
|
||||
|
||||
if ( ( fd = open( (const char*)port, O_RDWR ) ) >= 0 ) {
|
||||
wr_bytes( fd, reg, &v, 1 );
|
||||
close( fd );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool rtc_ds1375_device_probe(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if ( ( fd = getfd( minor ) ) < 0 ) {
|
||||
STDIOSAFE( "ds1375_probe (open): %s\n", strerror( errno ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Try to set file pointer */
|
||||
if ( 0 != wr_bytes( fd, DS1375_SEC_REG, 0, 0 ) ) {
|
||||
STDIOSAFE( "ds1375_probe (wr_bytes): %s\n", strerror( errno ) );
|
||||
close( fd );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( close( fd ) ) {
|
||||
STDIOSAFE( "ds1375_probe (close): %s\n", strerror( errno ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
rtc_fns rtc_ds1375_fns = {
|
||||
.deviceInitialize = ds1375_initialize,
|
||||
.deviceGetTime = ds1375_get_time,
|
||||
.deviceSetTime = ds1375_set_time,
|
||||
};
|
||||
168
bsps/shared/dev/rtc/icm7170.c
Normal file
168
bsps/shared/dev/rtc/icm7170.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* This file interfaces with the real-time clock found in
|
||||
* a Harris ICM7170
|
||||
*
|
||||
* Year 2K Notes:
|
||||
*
|
||||
* This chip only uses a two digit field to store the year. This
|
||||
* code uses the RTEMS Epoch as a pivot year. This lets us map the
|
||||
* two digit year field as follows:
|
||||
*
|
||||
* + two digit years 0-87 are mapped to 2000-2087.
|
||||
* + two digit years 88-99 are mapped to 1988-1999.
|
||||
*
|
||||
* This is less than the time span supported by RTEMS.
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1999.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <libchip/rtc.h>
|
||||
#include <libchip/icm7170.h>
|
||||
|
||||
/*
|
||||
* Control register bits
|
||||
*/
|
||||
|
||||
/* XXX */
|
||||
|
||||
/*
|
||||
* icm7170_initialize
|
||||
*/
|
||||
|
||||
static void icm7170_initialize(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
uintptr_t icm7170;
|
||||
setRegister_f setReg;
|
||||
uintptr_t clock;
|
||||
|
||||
icm7170 = RTC_Table[ minor ].ulCtrlPort1;
|
||||
setReg = RTC_Table[ minor ].setRegister;
|
||||
|
||||
/*
|
||||
* Initialize the RTC with the proper clock frequency
|
||||
*/
|
||||
|
||||
clock = (uintptr_t) RTC_Table[ minor ].pDeviceParams;
|
||||
(*setReg)( icm7170, ICM7170_CONTROL, 0x0c | clock );
|
||||
}
|
||||
|
||||
/*
|
||||
* icm7170_get_time
|
||||
*/
|
||||
|
||||
static int icm7170_get_time(
|
||||
int minor,
|
||||
rtems_time_of_day *time
|
||||
)
|
||||
{
|
||||
uint32_t icm7170;
|
||||
getRegister_f getReg;
|
||||
uint32_t year;
|
||||
|
||||
icm7170 = RTC_Table[ minor ].ulCtrlPort1;
|
||||
getReg = RTC_Table[ minor ].getRegister;
|
||||
|
||||
/*
|
||||
* Put the RTC into read mode
|
||||
*/
|
||||
|
||||
(void) (*getReg)( icm7170, ICM7170_COUNTER_HUNDREDTHS );
|
||||
|
||||
/*
|
||||
* Now get the time
|
||||
*/
|
||||
|
||||
|
||||
year = (*getReg)( icm7170, ICM7170_YEAR );
|
||||
if ( year < 88 )
|
||||
year += 2000;
|
||||
else
|
||||
year += 1900;
|
||||
|
||||
time->year = year;
|
||||
time->month = (*getReg)( icm7170, ICM7170_MONTH );
|
||||
time->day = (*getReg)( icm7170, ICM7170_DATE );
|
||||
time->hour = (*getReg)( icm7170, ICM7170_HOUR );
|
||||
time->minute = (*getReg)( icm7170, ICM7170_MINUTE );
|
||||
time->second = (*getReg)( icm7170, ICM7170_SECOND );
|
||||
|
||||
time->ticks = 0;
|
||||
|
||||
/*
|
||||
* Put the RTC back into normal mode.
|
||||
*/
|
||||
|
||||
(void) (*getReg)( icm7170, ICM7170_COUNTER_HUNDREDTHS );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* icm7170_set_time
|
||||
*/
|
||||
|
||||
static int icm7170_set_time(
|
||||
int minor,
|
||||
const rtems_time_of_day *time
|
||||
)
|
||||
{
|
||||
uintptr_t icm7170;
|
||||
setRegister_f setReg;
|
||||
uint32_t year;
|
||||
uintptr_t clock;
|
||||
|
||||
icm7170 = RTC_Table[ minor ].ulCtrlPort1;
|
||||
setReg = RTC_Table[ minor ].setRegister;
|
||||
clock = (uintptr_t) RTC_Table[ minor ].pDeviceParams;
|
||||
|
||||
year = time->year;
|
||||
|
||||
if ( year >= 2088 )
|
||||
rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
|
||||
|
||||
if ( year >= 2000 )
|
||||
year -= 2000;
|
||||
else
|
||||
year -= 1900;
|
||||
|
||||
(*setReg)( icm7170, ICM7170_CONTROL, 0x04 | clock );
|
||||
|
||||
(*setReg)( icm7170, ICM7170_YEAR, year );
|
||||
(*setReg)( icm7170, ICM7170_MONTH, time->month );
|
||||
(*setReg)( icm7170, ICM7170_DATE, time->day );
|
||||
(*setReg)( icm7170, ICM7170_HOUR, time->hour );
|
||||
(*setReg)( icm7170, ICM7170_MINUTE, time->minute );
|
||||
(*setReg)( icm7170, ICM7170_SECOND, time->second );
|
||||
|
||||
/*
|
||||
* This is not really right.
|
||||
*/
|
||||
|
||||
(*setReg)( icm7170, ICM7170_DAY_OF_WEEK, 1 );
|
||||
|
||||
/*
|
||||
* Put the RTC back into normal mode.
|
||||
*/
|
||||
|
||||
(*setReg)( icm7170, ICM7170_CONTROL, 0x0c | clock );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver function table
|
||||
*/
|
||||
|
||||
rtc_fns icm7170_fns = {
|
||||
icm7170_initialize,
|
||||
icm7170_get_time,
|
||||
icm7170_set_time
|
||||
};
|
||||
60
bsps/shared/dev/rtc/icm7170_reg.c
Normal file
60
bsps/shared/dev/rtc/icm7170_reg.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the icm7170 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are only byte-aligned (no address gaps)
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <libchip/rtc.h>
|
||||
#include <libchip/icm7170.h>
|
||||
|
||||
#ifndef _ICM7170_MULTIPLIER
|
||||
#define _ICM7170_MULTIPLIER 1
|
||||
#define _ICM7170_NAME(_X) _X
|
||||
#define _ICM7170_TYPE uint8_t
|
||||
#endif
|
||||
|
||||
#define CALCULATE_REGISTER_ADDRESS( _base, _reg ) \
|
||||
(_ICM7170_TYPE *)((_base) + ((_reg) * _ICM7170_MULTIPLIER ))
|
||||
|
||||
/*
|
||||
* ICM7170 Get Register Routine
|
||||
*/
|
||||
|
||||
uint32_t _ICM7170_NAME(icm7170_get_register)(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum
|
||||
)
|
||||
{
|
||||
_ICM7170_TYPE *port;
|
||||
|
||||
port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
|
||||
|
||||
return *port;
|
||||
}
|
||||
|
||||
/*
|
||||
* ICM7170 Set Register Routine
|
||||
*/
|
||||
|
||||
void _ICM7170_NAME(icm7170_set_register)(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum,
|
||||
uint32_t ucData
|
||||
)
|
||||
{
|
||||
_ICM7170_TYPE *port;
|
||||
|
||||
port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
|
||||
|
||||
*port = ucData;
|
||||
}
|
||||
20
bsps/shared/dev/rtc/icm7170_reg2.c
Normal file
20
bsps/shared/dev/rtc/icm7170_reg2.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the icm7170 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are on 16-bit boundaries
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define _ICM7170_MULTIPLIER 2
|
||||
#define _ICM7170_NAME(_X) _X##_2
|
||||
#define _ICM7170_TYPE uint8_t
|
||||
|
||||
#include "icm7170_reg.c"
|
||||
20
bsps/shared/dev/rtc/icm7170_reg4.c
Normal file
20
bsps/shared/dev/rtc/icm7170_reg4.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the icm7170 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are on 32-bit boundaries
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define _ICM7170_MULTIPLIER 4
|
||||
#define _ICM7170_NAME(_X) _X##_4
|
||||
#define _ICM7170_TYPE uint8_t
|
||||
|
||||
#include "icm7170_reg.c"
|
||||
20
bsps/shared/dev/rtc/icm7170_reg8.c
Normal file
20
bsps/shared/dev/rtc/icm7170_reg8.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the icm7170 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are on 64-bit boundaries
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define _ICM7170_MULTIPLIER 8
|
||||
#define _ICM7170_NAME(_X) _X##_8
|
||||
#define _ICM7170_TYPE uint8_t
|
||||
|
||||
#include "icm7170_reg.c"
|
||||
161
bsps/shared/dev/rtc/m48t08.c
Normal file
161
bsps/shared/dev/rtc/m48t08.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* This file interfaces with the real-time clock found in
|
||||
* a Mostek M48T08 or M48T18 or compatibles.
|
||||
*
|
||||
* Year 2K Notes:
|
||||
*
|
||||
* This chip only uses a two digit field to store the year. This
|
||||
* code uses the RTEMS Epoch as a pivot year. This lets us map the
|
||||
* two digit year field as follows:
|
||||
*
|
||||
* + two digit years 0-87 are mapped to 2000-2087.
|
||||
* + two digit years 88-99 are mapped to 1988-1999.
|
||||
*
|
||||
* This is less than the time span supported by RTEMS.
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1999.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <libchip/rtc.h>
|
||||
#include <libchip/m48t08.h>
|
||||
|
||||
/*
|
||||
* Control register bits
|
||||
*/
|
||||
|
||||
#define M48T08_CONTROL_WRITE 0x80
|
||||
#define M48T08_CONTROL_READ 0x40
|
||||
#define M48T08_CONTROL_SIGN 0x20
|
||||
|
||||
/*
|
||||
* m48t08_initialize
|
||||
*/
|
||||
|
||||
static void m48t08_initialize(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* m48t08_get_time
|
||||
*/
|
||||
|
||||
#define From_BCD( _x ) ((((_x) >> 4) * 10) + ((_x) & 0x0F))
|
||||
#define To_BCD( _x ) ((((_x) / 10) << 4) + ((_x) % 10))
|
||||
|
||||
static int m48t08_get_time(
|
||||
int minor,
|
||||
rtems_time_of_day *time
|
||||
)
|
||||
{
|
||||
uint32_t m48t08;
|
||||
getRegister_f getReg;
|
||||
setRegister_f setReg;
|
||||
uint8_t controlReg;
|
||||
uint32_t value1;
|
||||
uint32_t value2;
|
||||
|
||||
m48t08 = RTC_Table[ minor ].ulCtrlPort1;
|
||||
getReg = RTC_Table[ minor ].getRegister;
|
||||
setReg = RTC_Table[ minor ].setRegister;
|
||||
|
||||
/*
|
||||
* Put the RTC into read mode
|
||||
*/
|
||||
|
||||
controlReg = (*getReg)( m48t08, M48T08_CONTROL );
|
||||
(*setReg)( m48t08, M48T08_CONTROL, controlReg | M48T08_CONTROL_READ );
|
||||
|
||||
value1 = (*getReg)( m48t08, M48T08_YEAR );
|
||||
value2 = From_BCD( value1 );
|
||||
if ( value2 < 88 )
|
||||
time->year = 2000 + value2;
|
||||
else
|
||||
time->year = 1900 + value2;
|
||||
|
||||
value1 = (*getReg)( m48t08, M48T08_MONTH );
|
||||
time->month = From_BCD( value1 );
|
||||
|
||||
value1 = (*getReg)( m48t08, M48T08_DATE );
|
||||
time->day = From_BCD( value1 );
|
||||
|
||||
value1 = (*getReg)( m48t08, M48T08_HOUR );
|
||||
time->hour = From_BCD( value1 );
|
||||
|
||||
value1 = (*getReg)( m48t08, M48T08_MINUTE );
|
||||
time->minute = From_BCD( value1 );
|
||||
|
||||
value1 = (*getReg)( m48t08, M48T08_SECOND );
|
||||
time->second = From_BCD( value1 );
|
||||
|
||||
time->ticks = 0;
|
||||
|
||||
/*
|
||||
* Put the RTC back into normal mode.
|
||||
*/
|
||||
|
||||
(*setReg)( m48t08, M48T08_CONTROL, controlReg );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* m48t08_set_time
|
||||
*/
|
||||
|
||||
static int m48t08_set_time(
|
||||
int minor,
|
||||
const rtems_time_of_day *time
|
||||
)
|
||||
{
|
||||
uint32_t m48t08;
|
||||
getRegister_f getReg;
|
||||
setRegister_f setReg;
|
||||
uint8_t controlReg;
|
||||
|
||||
m48t08 = RTC_Table[ minor ].ulCtrlPort1;
|
||||
getReg = RTC_Table[ minor ].getRegister;
|
||||
setReg = RTC_Table[ minor ].setRegister;
|
||||
|
||||
/*
|
||||
* Put the RTC into read mode
|
||||
*/
|
||||
|
||||
controlReg = (*getReg)( m48t08, M48T08_CONTROL );
|
||||
(*setReg)( m48t08, M48T08_CONTROL, controlReg | M48T08_CONTROL_WRITE );
|
||||
|
||||
if ( time->year >= 2088 )
|
||||
rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
|
||||
|
||||
(*setReg)( m48t08, M48T08_YEAR, To_BCD(time->year % 100) );
|
||||
(*setReg)( m48t08, M48T08_MONTH, To_BCD(time->month) );
|
||||
(*setReg)( m48t08, M48T08_DATE, To_BCD(time->day) );
|
||||
(*setReg)( m48t08, M48T08_HOUR, To_BCD(time->hour) );
|
||||
(*setReg)( m48t08, M48T08_MINUTE, To_BCD(time->minute) );
|
||||
(*setReg)( m48t08, M48T08_SECOND, To_BCD(time->second) );
|
||||
|
||||
/*
|
||||
* Put the RTC back into normal mode.
|
||||
*/
|
||||
|
||||
(*setReg)( m48t08, M48T08_CONTROL, controlReg );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver function table
|
||||
*/
|
||||
|
||||
rtc_fns m48t08_fns = {
|
||||
m48t08_initialize,
|
||||
m48t08_get_time,
|
||||
m48t08_set_time
|
||||
};
|
||||
60
bsps/shared/dev/rtc/m48t08_reg.c
Normal file
60
bsps/shared/dev/rtc/m48t08_reg.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the m48t08 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are only byte-aligned (no address gaps)
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <libchip/rtc.h>
|
||||
#include <libchip/m48t08.h>
|
||||
|
||||
#ifndef _M48T08_MULTIPLIER
|
||||
#define _M48T08_MULTIPLIER 1
|
||||
#define _M48T08_NAME(_X) _X
|
||||
#define _M48T08_TYPE uint8_t
|
||||
#endif
|
||||
|
||||
#define CALCULATE_REGISTER_ADDRESS( _base, _reg ) \
|
||||
(_M48T08_TYPE *)((_base) + ((_reg) * _M48T08_MULTIPLIER ))
|
||||
|
||||
/*
|
||||
* M48T08 Get Register Routine
|
||||
*/
|
||||
|
||||
uint32_t _M48T08_NAME(m48t08_get_register)(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum
|
||||
)
|
||||
{
|
||||
_M48T08_TYPE *port;
|
||||
|
||||
port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
|
||||
|
||||
return *port;
|
||||
}
|
||||
|
||||
/*
|
||||
* M48T08 Set Register Routine
|
||||
*/
|
||||
|
||||
void _M48T08_NAME(m48t08_set_register)(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum,
|
||||
uint32_t ucData
|
||||
)
|
||||
{
|
||||
_M48T08_TYPE *port;
|
||||
|
||||
port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
|
||||
|
||||
*port = ucData;
|
||||
}
|
||||
20
bsps/shared/dev/rtc/m48t08_reg2.c
Normal file
20
bsps/shared/dev/rtc/m48t08_reg2.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the m48t08 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are on 16-bit boundaries
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define _M48T08_MULTIPLIER 2
|
||||
#define _M48T08_NAME(_X) _X##_2
|
||||
#define _M48T08_TYPE uint8_t
|
||||
|
||||
#include "m48t08_reg.c"
|
||||
20
bsps/shared/dev/rtc/m48t08_reg4.c
Normal file
20
bsps/shared/dev/rtc/m48t08_reg4.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the m48t08 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are on 32-bit boundaries
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define _M48T08_MULTIPLIER 4
|
||||
#define _M48T08_NAME(_X) _X##_4
|
||||
#define _M48T08_TYPE uint8_t
|
||||
|
||||
#include "m48t08_reg.c"
|
||||
20
bsps/shared/dev/rtc/m48t08_reg8.c
Normal file
20
bsps/shared/dev/rtc/m48t08_reg8.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the m48t08 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are on 64-bit boundaries
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define _M48T08_MULTIPLIER 8
|
||||
#define _M48T08_NAME(_X) _X##_8
|
||||
#define _M48T08_TYPE uint8_t
|
||||
|
||||
#include "m48t08_reg.c"
|
||||
180
bsps/shared/dev/rtc/mc146818a.c
Normal file
180
bsps/shared/dev/rtc/mc146818a.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* This file interfaces with the real-time clock found in
|
||||
* a Motorola MC146818A (common on PC hardware)
|
||||
*
|
||||
* Year 2K Notes:
|
||||
*
|
||||
* This chip only uses a two digit field to store the year. This
|
||||
* code uses the RTEMS Epoch as a pivot year. This lets us map the
|
||||
* two digit year field as follows:
|
||||
*
|
||||
* + two digit years 0-87 are mapped to 2000-2087.
|
||||
* + two digit years 88-99 are mapped to 1988-1999.
|
||||
*
|
||||
* This is less than the time span supported by RTEMS.
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1999.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
#include <rtems.h>
|
||||
#include <libchip/rtc.h>
|
||||
#include <libchip/mc146818a.h>
|
||||
|
||||
#define From_BCD( _x ) ((((_x) >> 4) * 10) + ((_x) & 0x0F))
|
||||
#define To_BCD( _x ) ((((_x) / 10) << 4) + ((_x) % 10))
|
||||
|
||||
/*
|
||||
* See if chip is present
|
||||
*/
|
||||
bool mc146818a_probe(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
uint32_t mc146818a;
|
||||
getRegister_f getReg;
|
||||
uint32_t value;
|
||||
|
||||
/*
|
||||
* Verify that chip is present and that time is valid
|
||||
*/
|
||||
mc146818a = RTC_Table[ minor ].ulCtrlPort1;
|
||||
getReg = RTC_Table[ minor ].getRegister;
|
||||
value = (*getReg)( mc146818a, MC146818A_STATUSD );
|
||||
if ((value == 0) || (value == 0xFF))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize chip
|
||||
*/
|
||||
static void mc146818a_initialize(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
uintptr_t mc146818a;
|
||||
setRegister_f setReg;
|
||||
|
||||
mc146818a = RTC_Table[ minor ].ulCtrlPort1;
|
||||
setReg = RTC_Table[ minor ].setRegister;
|
||||
|
||||
(*setReg)(
|
||||
mc146818a,
|
||||
MC146818A_STATUSA,
|
||||
MC146818ASA_DIVIDER|MC146818ASA_1024
|
||||
);
|
||||
(*setReg)(
|
||||
mc146818a,
|
||||
MC146818A_STATUSB,
|
||||
MC146818ASB_24HR
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read time from chip
|
||||
*/
|
||||
static int mc146818a_get_time(
|
||||
int minor,
|
||||
rtems_time_of_day *time
|
||||
)
|
||||
{
|
||||
uintptr_t mc146818a;
|
||||
getRegister_f getReg;
|
||||
uint32_t value;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
mc146818a = RTC_Table[ minor ].ulCtrlPort1;
|
||||
getReg = RTC_Table[ minor ].getRegister;
|
||||
|
||||
/*
|
||||
* No time if power failed
|
||||
*/
|
||||
if (((*getReg)( mc146818a, MC146818A_STATUSD ) & MC146818ASD_PWR) == 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Wait for time update to complete
|
||||
*/
|
||||
rtems_interrupt_disable( level );
|
||||
while (((*getReg)( mc146818a, MC146818A_STATUSA ) & MC146818ASA_TUP) != 0) {
|
||||
rtems_interrupt_flash( level );
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the time (we have at least 244 usec to do this)
|
||||
*/
|
||||
value = (*getReg)( mc146818a, MC146818A_YEAR );
|
||||
value = From_BCD( value );
|
||||
if ( value < 88 )
|
||||
time->year = 2000 + value;
|
||||
else
|
||||
time->year = 1900 + value;
|
||||
|
||||
value = (*getReg)( mc146818a, MC146818A_MONTH );
|
||||
time->month = From_BCD( value );
|
||||
|
||||
value = (*getReg)( mc146818a, MC146818A_DAY );
|
||||
time->day = From_BCD( value );
|
||||
|
||||
value = (*getReg)( mc146818a, MC146818A_HRS );
|
||||
time->hour = From_BCD( value );
|
||||
|
||||
value = (*getReg)( mc146818a, MC146818A_MIN );
|
||||
time->minute = From_BCD( value );
|
||||
|
||||
value = (*getReg)( mc146818a, MC146818A_SEC );
|
||||
rtems_interrupt_enable( level );
|
||||
time->second = From_BCD( value );
|
||||
time->ticks = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set time into chip
|
||||
*/
|
||||
static int mc146818a_set_time(
|
||||
int minor,
|
||||
const rtems_time_of_day *time
|
||||
)
|
||||
{
|
||||
uint32_t mc146818a;
|
||||
setRegister_f setReg;
|
||||
|
||||
mc146818a = RTC_Table[ minor ].ulCtrlPort1;
|
||||
setReg = RTC_Table[ minor ].setRegister;
|
||||
|
||||
/*
|
||||
* Stop the RTC
|
||||
*/
|
||||
(*setReg)( mc146818a, MC146818A_STATUSB, MC146818ASB_HALT|MC146818ASB_24HR );
|
||||
|
||||
if ( time->year >= 2088 )
|
||||
rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
|
||||
|
||||
(*setReg)( mc146818a, MC146818A_YEAR, To_BCD(time->year % 100) );
|
||||
(*setReg)( mc146818a, MC146818A_MONTH, To_BCD(time->month) );
|
||||
(*setReg)( mc146818a, MC146818A_DAY, To_BCD(time->day) );
|
||||
(*setReg)( mc146818a, MC146818A_HRS, To_BCD(time->hour) );
|
||||
(*setReg)( mc146818a, MC146818A_MIN, To_BCD(time->minute) );
|
||||
(*setReg)( mc146818a, MC146818A_SEC, To_BCD(time->second) );
|
||||
|
||||
/*
|
||||
* Restart the RTC
|
||||
*/
|
||||
(*setReg)( mc146818a, MC146818A_STATUSB, MC146818ASB_24HR );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver function table
|
||||
*/
|
||||
rtc_fns mc146818a_fns = {
|
||||
mc146818a_initialize,
|
||||
mc146818a_get_time,
|
||||
mc146818a_set_time
|
||||
};
|
||||
56
bsps/shared/dev/rtc/mc146818a_ioreg.c
Normal file
56
bsps/shared/dev/rtc/mc146818a_ioreg.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the MC146818A chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are in I/O space
|
||||
* + registers are accessed as bytes
|
||||
* + registers are only byte-aligned (no address gaps)
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <bsp.h>
|
||||
#include <libchip/rtc.h>
|
||||
#include <libchip/mc146818a.h>
|
||||
|
||||
/*
|
||||
* At this point, not all CPUs or BSPs have defined in/out port routines.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__PPC__)
|
||||
#if defined(inport_byte)
|
||||
uint32_t mc146818a_get_register(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum
|
||||
)
|
||||
{
|
||||
uint8_t val;
|
||||
uint8_t tmp;
|
||||
|
||||
(void) tmp; /* eliminate warning for set but not used */
|
||||
|
||||
outport_byte( ulCtrlPort, ucRegNum );
|
||||
inport_byte( 0x84, tmp ); /* Hack a delay to give chip time to settle */
|
||||
inport_byte( ulCtrlPort+1, val );
|
||||
inport_byte( 0x84, tmp ); /* Hack a delay to give chip time to settle */
|
||||
return val;
|
||||
}
|
||||
|
||||
void mc146818a_set_register(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum,
|
||||
uint32_t ucData
|
||||
)
|
||||
{
|
||||
outport_byte( ulCtrlPort, ucRegNum );
|
||||
outport_byte( ulCtrlPort+1, (uint8_t)ucData );
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
21
bsps/shared/dev/rtc/rtcprobe.c
Normal file
21
bsps/shared/dev/rtc/rtcprobe.c
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file contains the default Real-Time Clock probe routine.
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1999.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <libchip/rtc.h>
|
||||
|
||||
|
||||
bool rtc_probe(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
13
bsps/shared/dev/serial/README
Normal file
13
bsps/shared/dev/serial/README
Normal file
@@ -0,0 +1,13 @@
|
||||
This is the serial controller portion of the libchip library. This
|
||||
directory contains the source code for reusable console driver
|
||||
support code. Each individual driver is configured using the
|
||||
console_tbl data structure. This structure is defined and explained
|
||||
in the console.h file.
|
||||
|
||||
The reusable chip drivers do not directly access the serial controller.
|
||||
They access the registers on the controller via a set of up to four
|
||||
functions which are provided by the BSP. These functins set and get
|
||||
general registers and data buffers. Some chips can access the data
|
||||
buffers as general registers and thus the driver may not require
|
||||
those interface routines.
|
||||
|
||||
83
bsps/shared/dev/serial/README.mc68681
Normal file
83
bsps/shared/dev/serial/README.mc68681
Normal file
@@ -0,0 +1,83 @@
|
||||
Configuration Table Use
|
||||
=======================
|
||||
|
||||
sDeviceName
|
||||
|
||||
The name of this device.
|
||||
|
||||
deviceType
|
||||
|
||||
This field must be SERIAL_MC68681.
|
||||
|
||||
pDeviceFns
|
||||
|
||||
The device interface control table. This may be:
|
||||
+ mc68681_fns for interrupt driven IO
|
||||
+ mc68681_fns_polled for polled IO
|
||||
|
||||
deviceProbe
|
||||
|
||||
This is the address of the routine which probes to see if the device
|
||||
is present.
|
||||
|
||||
pDeviceFlow
|
||||
|
||||
This field is ignored as hardware flow control is not currently supported.
|
||||
|
||||
ulMargin
|
||||
|
||||
This is currently unused.
|
||||
|
||||
ulHysteresis
|
||||
|
||||
This is currently unused.
|
||||
|
||||
pDeviceParams
|
||||
|
||||
This is set to the default settings.
|
||||
|
||||
ulCtrlPort1
|
||||
|
||||
This field is the base address of the entire DUART.
|
||||
|
||||
ulCtrlPort2
|
||||
|
||||
This field is the base address of the port specific registers.
|
||||
|
||||
ulDataPort
|
||||
|
||||
This field is bit mapped as follows:
|
||||
bit 0: baud rate set a or b
|
||||
bit 1-2: BRG selection ("Select Extend bit")
|
||||
|
||||
Note: If both ports on single DUART are not configured for the same
|
||||
baud rate set, then unexpected results will occur.
|
||||
|
||||
Note: On the Exar 88c681, if a standard clock of 3.6864 Mhz is used
|
||||
and the "Select Extend bit" is 0 (disabled), then the default
|
||||
MC68681 baud rate table is selected.
|
||||
|
||||
getRegister
|
||||
setRegister
|
||||
|
||||
These follow standard conventions.
|
||||
|
||||
getData
|
||||
setData
|
||||
|
||||
These are unused since the TX and RX data registers can be accessed
|
||||
as regular registers.
|
||||
|
||||
ulClock
|
||||
|
||||
This is a pointer to a baud rate mapping table. If set to
|
||||
mc68681_baud_rate_table, then the CSR/ACR/X bit mappings shown
|
||||
in the 68681 and 88681 manuals are used. Otherwise, the board
|
||||
specific baud rate mapping is used.
|
||||
|
||||
NULL is not a valid value.
|
||||
|
||||
ulIntVector
|
||||
|
||||
This is the interrupt vector number associated with this chip.
|
||||
|
||||
82
bsps/shared/dev/serial/README.ns16550
Normal file
82
bsps/shared/dev/serial/README.ns16550
Normal file
@@ -0,0 +1,82 @@
|
||||
Status
|
||||
======
|
||||
|
||||
There are no known problems with this driver.
|
||||
|
||||
Configuration Table Use
|
||||
=======================
|
||||
|
||||
sDeviceName
|
||||
|
||||
The name of this device.
|
||||
|
||||
deviceType
|
||||
|
||||
This field must be SERIAL_NS16550.
|
||||
|
||||
pDeviceFns
|
||||
|
||||
The device interface control table. This may be:
|
||||
+ ns16550_fns for interrupt driven IO
|
||||
+ ns16550_fns_polled for polled IO
|
||||
|
||||
deviceProbe
|
||||
|
||||
This is the address of the routine which probes to see if the device
|
||||
is present.
|
||||
|
||||
pDeviceFlow
|
||||
|
||||
This field is ignored as hardware flow control is not currently supported.
|
||||
|
||||
ulMargin
|
||||
|
||||
This is currently unused.
|
||||
|
||||
ulHysteresis
|
||||
|
||||
This is currently unused.
|
||||
|
||||
pDeviceParams
|
||||
|
||||
This is set to the default settings. At this point, it is the default
|
||||
baud rate cast as a (void *).
|
||||
|
||||
ulCtrlPort1
|
||||
|
||||
This field is the base address of this port on the UART.
|
||||
|
||||
ulCtrlPort2
|
||||
|
||||
This field is unused for the NS16550.
|
||||
|
||||
ulDataPort
|
||||
|
||||
This field is the base address of this port on the UART.
|
||||
|
||||
getRegister
|
||||
setRegister
|
||||
|
||||
These follow standard conventions.
|
||||
|
||||
getData
|
||||
setData
|
||||
|
||||
These are unused since the TX and RX data registers can be accessed
|
||||
as regular registers.
|
||||
|
||||
ulClock
|
||||
|
||||
This is the clock constant which is divided by the desired baud
|
||||
to get the value programmed into the part. The formula for this
|
||||
for 9600 baud is:
|
||||
|
||||
chip_divisor_value = ulClock / 9600.
|
||||
|
||||
NOTE: When ulClock is 0, the correct value for a PC (115,200) is
|
||||
used.
|
||||
|
||||
ulIntVector
|
||||
|
||||
This is the interrupt vector number associated with this chip.
|
||||
|
||||
2
bsps/shared/dev/serial/README.xr88681
Normal file
2
bsps/shared/dev/serial/README.xr88681
Normal file
@@ -0,0 +1,2 @@
|
||||
The Exar XR88681 is an enhanced version of the Motorola MC68681 and is
|
||||
supported by the mc68681 driver.
|
||||
74
bsps/shared/dev/serial/README.z85c30
Normal file
74
bsps/shared/dev/serial/README.z85c30
Normal file
@@ -0,0 +1,74 @@
|
||||
Configuration Table Use
|
||||
=======================
|
||||
|
||||
sDeviceName
|
||||
|
||||
The name of this device.
|
||||
|
||||
deviceType
|
||||
|
||||
This field must be SERIAL_Z85C30.
|
||||
|
||||
pDeviceFns
|
||||
|
||||
The device interface control table. This may be:
|
||||
+ z85c30_fns for interrupt driven IO
|
||||
+ z85c30_fns_polled for polled IO
|
||||
|
||||
deviceProbe
|
||||
|
||||
This is the address of the routine which probes to see if the device
|
||||
is present.
|
||||
|
||||
pDeviceFlow
|
||||
|
||||
This field is set to one of the following values:
|
||||
+ NULL for no hardware flow control
|
||||
+ z85c30_flow_RTSCTS for RTS/CTS based flow control
|
||||
+ z85c30_flow_DTRCTS for DTR/CTS based flow control
|
||||
|
||||
ulMargin
|
||||
|
||||
This is currently unused.
|
||||
|
||||
ulHysteresis
|
||||
|
||||
This is currently unused.
|
||||
|
||||
pDeviceParams
|
||||
|
||||
This is set to the default settings.
|
||||
|
||||
ulCtrlPort1
|
||||
|
||||
This field is the address of the control register for this port.
|
||||
|
||||
ulCtrlPort2
|
||||
|
||||
This field is the address of the control register for chip.
|
||||
|
||||
ulDataPort
|
||||
|
||||
This field is the address of the data register for this port.
|
||||
|
||||
getRegister
|
||||
setRegister
|
||||
|
||||
These follow standard conventions.
|
||||
|
||||
getData
|
||||
setData
|
||||
|
||||
These follow standard conventions.
|
||||
|
||||
ulClock
|
||||
|
||||
This is the clock speed of the baud rate clock.
|
||||
NULL, then the CSR/ACR/X bit mappings shown in the 68681 and 88681
|
||||
manuals are used. Otherwise, the board specific baud rate mapping
|
||||
is used.
|
||||
|
||||
ulIntVector
|
||||
|
||||
This is the interrupt vector number associated with this chip.
|
||||
|
||||
48
bsps/shared/dev/serial/STATUS
Normal file
48
bsps/shared/dev/serial/STATUS
Normal file
@@ -0,0 +1,48 @@
|
||||
General
|
||||
=======
|
||||
|
||||
+ Hardware flow control is not currently supported. Some of the chip
|
||||
drivers (in particular the z8530) have support for hardware flow control
|
||||
but this has not been tested in the libchip context. There will need
|
||||
to be a way to totally disabled hardware flow control which is not
|
||||
currently in this.
|
||||
|
||||
+ "ulClockSpeed" configuration item field to become a pointer to a table
|
||||
of chip specific information. For example, the z8530 should specify
|
||||
clock speed and clock divisor setting.
|
||||
|
||||
+ A termios structure should be included to specify the initial settings.
|
||||
Right now all drivers default to 9600, 8N1.
|
||||
|
||||
+ Need to switch to passing pointers rather than a minor number to
|
||||
functions which are strictly internal to each chip driver. This
|
||||
should be a performance win.
|
||||
|
||||
+ Need a test which prompts you for termios settings and tests them. Until
|
||||
this happens, testing for the variety of settings possible will be limited.
|
||||
This test should be able to test any serial port while prompts come to the
|
||||
console.
|
||||
|
||||
MC68681
|
||||
=======
|
||||
|
||||
+ Works interrupt and polled.
|
||||
|
||||
+ Hardware flow control not included.
|
||||
|
||||
NS16650
|
||||
=======
|
||||
|
||||
+ ns16550_set-attributes function is untested.
|
||||
|
||||
+ Hardware flow control included but is currently disabled in ISR.
|
||||
|
||||
Z85C30
|
||||
======
|
||||
|
||||
+ Works polled and interrupt.
|
||||
|
||||
+ Hardware flow control included but is currently disabled in ISR.
|
||||
|
||||
+ Needs to support mode where more specific vectors are generated.
|
||||
|
||||
776
bsps/shared/dev/serial/mc68681.c
Normal file
776
bsps/shared/dev/serial/mc68681.c
Normal file
@@ -0,0 +1,776 @@
|
||||
/*
|
||||
* This file contains the termios TTY driver for the Motorola MC68681.
|
||||
*
|
||||
* This part is available from a number of secondary sources.
|
||||
* In particular, we know about the following:
|
||||
*
|
||||
* + Exar 88c681 and 68c681
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1999.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/score/sysstate.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <libchip/serial.h>
|
||||
#include <libchip/mc68681.h>
|
||||
#include <libchip/sersupp.h>
|
||||
#include "mc68681_p.h"
|
||||
|
||||
/*
|
||||
* Flow control is only supported when using interrupts
|
||||
*/
|
||||
|
||||
const console_fns mc68681_fns =
|
||||
{
|
||||
libchip_serial_default_probe, /* deviceProbe */
|
||||
mc68681_open, /* deviceFirstOpen */
|
||||
NULL, /* deviceLastClose */
|
||||
NULL, /* deviceRead */
|
||||
mc68681_write_support_int, /* deviceWrite */
|
||||
mc68681_initialize_interrupts, /* deviceInitialize */
|
||||
mc68681_write_polled, /* deviceWritePolled */
|
||||
mc68681_set_attributes, /* deviceSetAttributes */
|
||||
true /* deviceOutputUsesInterrupts */
|
||||
};
|
||||
|
||||
const console_fns mc68681_fns_polled =
|
||||
{
|
||||
libchip_serial_default_probe, /* deviceProbe */
|
||||
mc68681_open, /* deviceFirstOpen */
|
||||
mc68681_close, /* deviceLastClose */
|
||||
mc68681_inbyte_nonblocking_polled, /* deviceRead */
|
||||
mc68681_write_support_polled, /* deviceWrite */
|
||||
mc68681_init, /* deviceInitialize */
|
||||
mc68681_write_polled, /* deviceWritePolled */
|
||||
mc68681_set_attributes, /* deviceSetAttributes */
|
||||
false, /* deviceOutputUsesInterrupts */
|
||||
};
|
||||
|
||||
|
||||
#if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
|
||||
extern void set_vector( rtems_isr_entry, rtems_vector_number, int );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Console Device Driver Entry Points
|
||||
*/
|
||||
|
||||
/*
|
||||
* mc68681_baud_rate
|
||||
*
|
||||
* This routine returns the proper ACR bit and baud rate field values
|
||||
* based on the requested baud rate. The baud rate set to be used
|
||||
* must be configured by the user.
|
||||
*/
|
||||
|
||||
MC68681_STATIC int mc68681_baud_rate(
|
||||
int minor,
|
||||
int baud,
|
||||
unsigned int *baud_mask_p,
|
||||
unsigned int *acr_bit_p,
|
||||
unsigned int *command
|
||||
);
|
||||
|
||||
/*
|
||||
* mc68681_set_attributes
|
||||
*
|
||||
* This function sets the DUART channel to reflect the requested termios
|
||||
* port settings.
|
||||
*/
|
||||
|
||||
MC68681_STATIC int mc68681_set_attributes(
|
||||
int minor,
|
||||
const struct termios *t
|
||||
)
|
||||
{
|
||||
uint32_t pMC68681_port;
|
||||
uint32_t pMC68681;
|
||||
unsigned int mode1;
|
||||
unsigned int mode2;
|
||||
unsigned int baud_mask;
|
||||
unsigned int acr_bit;
|
||||
unsigned int cmd = 0;
|
||||
setRegister_f setReg;
|
||||
rtems_interrupt_level Irql;
|
||||
|
||||
pMC68681 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Set the baud rate
|
||||
*/
|
||||
|
||||
if (mc68681_baud_rate( minor, t->c_cflag, &baud_mask, &acr_bit, &cmd ) == -1)
|
||||
return -1;
|
||||
|
||||
baud_mask |= baud_mask << 4;
|
||||
acr_bit <<= 7;
|
||||
|
||||
/*
|
||||
* Parity
|
||||
*/
|
||||
|
||||
mode1 = 0;
|
||||
mode2 = 0;
|
||||
|
||||
if (t->c_cflag & PARENB) {
|
||||
if (t->c_cflag & PARODD)
|
||||
mode1 |= 0x04;
|
||||
/* else
|
||||
mode1 |= 0x04; */
|
||||
} else {
|
||||
mode1 |= 0x10;
|
||||
}
|
||||
|
||||
/*
|
||||
* Character Size
|
||||
*/
|
||||
|
||||
if (t->c_cflag & CSIZE) {
|
||||
switch (t->c_cflag & CSIZE) {
|
||||
case CS5: break;
|
||||
case CS6: mode1 |= 0x01; break;
|
||||
case CS7: mode1 |= 0x02; break;
|
||||
case CS8: mode1 |= 0x03; break;
|
||||
}
|
||||
} else {
|
||||
mode1 |= 0x03; /* default to 9600,8,N,1 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop Bits
|
||||
*/
|
||||
|
||||
if (t->c_cflag & CSTOPB) {
|
||||
mode2 |= 0x0F; /* 2 stop bits */
|
||||
} else {
|
||||
if ((t->c_cflag & CSIZE) == CS5) /* CS5 and 1 stop bits not supported */
|
||||
return -1;
|
||||
mode2 |= 0x07; /* 1 stop bit */
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardware Flow Control
|
||||
*/
|
||||
|
||||
if(t->c_cflag & CRTSCTS) {
|
||||
mode1 |= 0x80; /* Enable Rx RTS Control */
|
||||
mode2 |= 0x10; /* Enable CTS Enable Tx */
|
||||
}
|
||||
|
||||
|
||||
rtems_interrupt_disable(Irql);
|
||||
(*setReg)( pMC68681, MC68681_AUX_CTRL_REG, acr_bit );
|
||||
(*setReg)( pMC68681_port, MC68681_CLOCK_SELECT, baud_mask );
|
||||
if ( cmd ) {
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, cmd ); /* RX */
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, cmd | 0x20 ); /* TX */
|
||||
}
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_MR_PTR );
|
||||
(*setReg)( pMC68681_port, MC68681_MODE, mode1 );
|
||||
(*setReg)( pMC68681_port, MC68681_MODE, mode2 );
|
||||
rtems_interrupt_enable(Irql);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_initialize_context
|
||||
*
|
||||
* This function sets the default values of the per port context structure.
|
||||
*/
|
||||
|
||||
MC68681_STATIC void mc68681_initialize_context(
|
||||
int minor,
|
||||
mc68681_context *pmc68681Context
|
||||
)
|
||||
{
|
||||
int port;
|
||||
unsigned int pMC68681;
|
||||
unsigned int pMC68681_port;
|
||||
|
||||
pMC68681 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
|
||||
pmc68681Context->mate = -1;
|
||||
|
||||
for (port=0 ; port<Console_Port_Count ; port++ ) {
|
||||
if ( Console_Port_Tbl[port]->ulCtrlPort1 == pMC68681 &&
|
||||
Console_Port_Tbl[port]->ulCtrlPort2 != pMC68681_port ) {
|
||||
pmc68681Context->mate = port;
|
||||
pmc68681Context->imr = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_init
|
||||
*
|
||||
* This function initializes the DUART to a quiecsent state.
|
||||
*/
|
||||
|
||||
MC68681_STATIC void mc68681_init(int minor)
|
||||
{
|
||||
uint32_t pMC68681_port;
|
||||
mc68681_context *pmc68681Context;
|
||||
setRegister_f setReg;
|
||||
|
||||
pmc68681Context = (mc68681_context *) malloc(sizeof(mc68681_context));
|
||||
|
||||
Console_Port_Data[minor].pDeviceContext = (void *)pmc68681Context;
|
||||
|
||||
mc68681_initialize_context( minor, pmc68681Context );
|
||||
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Reset everything and leave this port disabled.
|
||||
*/
|
||||
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_RX );
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_TX );
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_ERROR );
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_BREAK );
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_STOP_BREAK );
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_TX );
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_RX );
|
||||
|
||||
|
||||
(*setReg)( pMC68681_port, MC68681_MODE_REG_1A, 0x00 );
|
||||
(*setReg)( pMC68681_port, MC68681_MODE_REG_2A, 0x02 );
|
||||
|
||||
/*
|
||||
* Disable interrupts on RX and TX for this port
|
||||
*/
|
||||
|
||||
mc68681_enable_interrupts( minor, MC68681_IMR_DISABLE_ALL );
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_open
|
||||
*
|
||||
* This function opens a port for communication.
|
||||
*
|
||||
* Default state is 9600 baud, 8 bits, No parity, and 1 stop bit.
|
||||
*/
|
||||
|
||||
MC68681_STATIC int mc68681_open(
|
||||
int major,
|
||||
int minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
uint32_t pMC68681;
|
||||
uint32_t pMC68681_port;
|
||||
unsigned int baud;
|
||||
unsigned int acr_bit;
|
||||
unsigned int vector;
|
||||
unsigned int command = 0;
|
||||
rtems_interrupt_level Irql;
|
||||
setRegister_f setReg;
|
||||
int status;
|
||||
|
||||
|
||||
pMC68681 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
vector = Console_Port_Tbl[minor]->ulIntVector;
|
||||
|
||||
/* XXX default baud rate should be from configuration table */
|
||||
|
||||
status = mc68681_baud_rate( minor, B9600, &baud, &acr_bit, &command );
|
||||
if (status < 0) rtems_fatal_error_occurred (RTEMS_NOT_DEFINED);
|
||||
|
||||
/*
|
||||
* Set the DUART channel to a default useable state
|
||||
*/
|
||||
|
||||
rtems_interrupt_disable(Irql);
|
||||
(*setReg)( pMC68681, MC68681_AUX_CTRL_REG, acr_bit << 7 );
|
||||
(*setReg)( pMC68681_port, MC68681_CLOCK_SELECT, baud );
|
||||
if ( command ) {
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, command ); /* RX */
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, command | 0x20 ); /* TX */
|
||||
}
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_MR_PTR );
|
||||
(*setReg)( pMC68681_port, MC68681_MODE, 0x13 );
|
||||
(*setReg)( pMC68681_port, MC68681_MODE, 0x07 );
|
||||
rtems_interrupt_enable(Irql);
|
||||
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_ENABLE_TX );
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_ENABLE_RX );
|
||||
|
||||
(*setReg)( pMC68681, MC68681_INTERRUPT_VECTOR_REG, vector );
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_close
|
||||
*
|
||||
* This function shuts down the requested port.
|
||||
*/
|
||||
|
||||
MC68681_STATIC int mc68681_close(
|
||||
int major,
|
||||
int minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
uint32_t pMC68681_port;
|
||||
setRegister_f setReg;
|
||||
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Disable interrupts from this channel and then disable it totally.
|
||||
*/
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_TX );
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_RX );
|
||||
|
||||
return(RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_write_polled
|
||||
*
|
||||
* This routine polls out the requested character.
|
||||
*/
|
||||
|
||||
MC68681_STATIC void mc68681_write_polled(
|
||||
int minor,
|
||||
char cChar
|
||||
)
|
||||
{
|
||||
uint32_t pMC68681_port;
|
||||
unsigned char ucLineStatus;
|
||||
int iTimeout;
|
||||
getRegister_f getReg;
|
||||
setRegister_f setReg;
|
||||
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
getReg = Console_Port_Tbl[minor]->getRegister;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* wait for transmitter holding register to be empty
|
||||
*/
|
||||
iTimeout = 1000;
|
||||
ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
|
||||
while ((ucLineStatus & (MC68681_TX_READY|MC68681_TX_EMPTY)) == 0) {
|
||||
|
||||
if ((ucLineStatus & 0xF0))
|
||||
(*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_ERROR );
|
||||
|
||||
/*
|
||||
* Yield while we wait
|
||||
*/
|
||||
|
||||
#if 0
|
||||
if(_System_state_Is_up(_System_state_Get())) {
|
||||
rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
|
||||
}
|
||||
#endif
|
||||
ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
|
||||
if(!--iTimeout) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* transmit character
|
||||
*/
|
||||
|
||||
(*setReg)(pMC68681_port, MC68681_TX_BUFFER, cChar);
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_isr
|
||||
*
|
||||
* This is the single interrupt entry point which parcels interrupts
|
||||
* out to the various ports.
|
||||
*/
|
||||
|
||||
MC68681_STATIC rtems_isr mc68681_isr(
|
||||
rtems_vector_number vector
|
||||
)
|
||||
{
|
||||
int minor;
|
||||
|
||||
for(minor=0 ; minor<Console_Port_Count ; minor++) {
|
||||
if(Console_Port_Tbl[minor]->ulIntVector == vector &&
|
||||
Console_Port_Tbl[minor]->deviceType == SERIAL_MC68681 ) {
|
||||
mc68681_process(minor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_initialize_interrupts
|
||||
*
|
||||
* This routine initializes the console's receive and transmit
|
||||
* ring buffers and loads the appropriate vectors to handle the interrupts.
|
||||
*/
|
||||
|
||||
MC68681_STATIC void mc68681_initialize_interrupts(int minor)
|
||||
{
|
||||
mc68681_init(minor);
|
||||
|
||||
Console_Port_Data[minor].bActive = FALSE;
|
||||
|
||||
#if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
|
||||
set_vector(mc68681_isr, Console_Port_Tbl[minor]->ulIntVector, 1);
|
||||
#endif
|
||||
|
||||
mc68681_enable_interrupts(minor,MC68681_IMR_ENABLE_ALL_EXCEPT_TX);
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_write_support_int
|
||||
*
|
||||
* Console Termios output entry point when using interrupt driven output.
|
||||
*/
|
||||
|
||||
MC68681_STATIC ssize_t mc68681_write_support_int(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
uint32_t Irql;
|
||||
uint32_t pMC68681_port;
|
||||
setRegister_f setReg;
|
||||
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* We are using interrupt driven output and termios only sends us
|
||||
* one character at a time.
|
||||
*/
|
||||
|
||||
if ( !len )
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Put the character out and enable interrupts if necessary.
|
||||
*/
|
||||
|
||||
rtems_interrupt_disable(Irql);
|
||||
if ( Console_Port_Data[minor].bActive == FALSE ) {
|
||||
Console_Port_Data[minor].bActive = TRUE;
|
||||
mc68681_enable_interrupts(minor, MC68681_IMR_ENABLE_ALL);
|
||||
}
|
||||
(*setReg)(pMC68681_port, MC68681_TX_BUFFER, *buf);
|
||||
rtems_interrupt_enable(Irql);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_write_support_polled
|
||||
*
|
||||
* Console Termios output entry point when using polled output.
|
||||
*
|
||||
*/
|
||||
|
||||
MC68681_STATIC ssize_t mc68681_write_support_polled(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
int nwrite = 0;
|
||||
|
||||
/*
|
||||
* poll each byte in the string out of the port.
|
||||
*/
|
||||
while (nwrite < len) {
|
||||
/*
|
||||
* transmit character
|
||||
*/
|
||||
mc68681_write_polled(minor, *buf++);
|
||||
nwrite++;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the number of bytes written.
|
||||
*/
|
||||
return nwrite;
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_inbyte_nonblocking_polled
|
||||
*
|
||||
* Console Termios polling input entry point.
|
||||
*/
|
||||
|
||||
MC68681_STATIC int mc68681_inbyte_nonblocking_polled(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
uint32_t pMC68681_port;
|
||||
unsigned char ucLineStatus;
|
||||
unsigned char cChar;
|
||||
getRegister_f getReg;
|
||||
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
getReg = Console_Port_Tbl[minor]->getRegister;
|
||||
|
||||
ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
|
||||
if(ucLineStatus & MC68681_RX_READY) {
|
||||
cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
|
||||
return (int)cChar;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_baud_rate
|
||||
*/
|
||||
|
||||
MC68681_STATIC int mc68681_baud_rate(
|
||||
int minor,
|
||||
int baud,
|
||||
unsigned int *baud_mask_p,
|
||||
unsigned int *acr_bit_p,
|
||||
unsigned int *command
|
||||
)
|
||||
{
|
||||
unsigned int baud_mask;
|
||||
unsigned int acr_bit;
|
||||
int status;
|
||||
int is_extended;
|
||||
int baud_requested;
|
||||
mc68681_baud_table_t *baud_tbl;
|
||||
|
||||
baud_mask = 0;
|
||||
acr_bit = 0;
|
||||
status = 0;
|
||||
|
||||
if (Console_Port_Tbl[minor]->ulDataPort & MC68681_DATA_BAUD_RATE_SET_2)
|
||||
{
|
||||
acr_bit = 1;
|
||||
}
|
||||
|
||||
is_extended = 0;
|
||||
|
||||
switch (Console_Port_Tbl[minor]->ulDataPort & MC68681_XBRG_MASK) {
|
||||
case MC68681_XBRG_IGNORED:
|
||||
*command = 0x00;
|
||||
break;
|
||||
case MC68681_XBRG_ENABLED:
|
||||
*command = 0x80;
|
||||
is_extended = 1;
|
||||
break;
|
||||
case MC68681_XBRG_DISABLED:
|
||||
*command = 0x90;
|
||||
break;
|
||||
}
|
||||
|
||||
baud_requested = baud;
|
||||
if (!baud_requested)
|
||||
baud_requested = B9600; /* default to 9600 baud */
|
||||
|
||||
baud_requested = rtems_termios_baud_to_index( baud_requested );
|
||||
if (baud_requested == -1)
|
||||
return -1;
|
||||
|
||||
baud_tbl = (mc68681_baud_table_t *)
|
||||
((uintptr_t)Console_Port_Tbl[minor]->ulClock);
|
||||
if (!baud_tbl)
|
||||
rtems_fatal_error_occurred(RTEMS_INVALID_ADDRESS);
|
||||
|
||||
if ( is_extended )
|
||||
baud_mask = (unsigned int)baud_tbl[ acr_bit + 2 ][ baud_requested ];
|
||||
else
|
||||
baud_mask = baud_tbl[ acr_bit ][ baud_requested ];
|
||||
|
||||
if ( baud_mask == MC68681_BAUD_NOT_VALID )
|
||||
status = -1;
|
||||
|
||||
/*
|
||||
* upper nibble is receiver and lower nibble is transmitter
|
||||
*/
|
||||
|
||||
*baud_mask_p = (baud_mask << 4) | baud_mask;
|
||||
*acr_bit_p = acr_bit;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_process
|
||||
*
|
||||
* This routine is the per port console interrupt handler.
|
||||
*/
|
||||
|
||||
MC68681_STATIC void mc68681_process(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
uint32_t pMC68681;
|
||||
uint32_t pMC68681_port;
|
||||
volatile uint8_t ucLineStatus;
|
||||
volatile uint8_t ucISRStatus;
|
||||
char cChar;
|
||||
getRegister_f getReg;
|
||||
|
||||
pMC68681 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
getReg = Console_Port_Tbl[minor]->getRegister;
|
||||
|
||||
/* Get ISR at the beginning of the IT routine */
|
||||
ucISRStatus = (*getReg)(pMC68681, MC68681_INTERRUPT_STATUS_REG);
|
||||
|
||||
/* Get good ISR a or b channel */
|
||||
if (pMC68681 != pMC68681_port){
|
||||
ucISRStatus >>= 4;
|
||||
}
|
||||
|
||||
/* See if is usefull to call rtems_termios_dequeue */
|
||||
if(Console_Port_Data[minor].bActive == FALSE) {
|
||||
ucISRStatus = ucISRStatus & ~MC68681_IR_TX_READY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deal with any received characters
|
||||
*/
|
||||
while(true) {
|
||||
ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
|
||||
if(!(ucLineStatus & MC68681_RX_READY)) {
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If there is a RX error, then dump all the data.
|
||||
*/
|
||||
if ( ucLineStatus & MC68681_RX_ERRORS ) {
|
||||
do {
|
||||
cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
|
||||
ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
|
||||
} while ( ucLineStatus & MC68681_RX_READY );
|
||||
continue;
|
||||
}
|
||||
cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
|
||||
rtems_termios_enqueue_raw_characters(
|
||||
Console_Port_Data[minor].termios_data,
|
||||
&cChar,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deal with the transmitter
|
||||
*/
|
||||
|
||||
if (ucISRStatus & MC68681_IR_TX_READY) {
|
||||
if (!rtems_termios_dequeue_characters(
|
||||
Console_Port_Data[minor].termios_data, 1)) {
|
||||
/* If no more char to send, disable TX interrupt */
|
||||
Console_Port_Data[minor].bActive = FALSE;
|
||||
mc68681_enable_interrupts(minor, MC68681_IMR_ENABLE_ALL_EXCEPT_TX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_build_imr
|
||||
*
|
||||
* This function returns the value for the interrupt mask register for this
|
||||
* DUART. Since this is a shared register, we must look at the other port
|
||||
* on this chip to determine whether or not it is using interrupts.
|
||||
*/
|
||||
|
||||
MC68681_STATIC unsigned int mc68681_build_imr(
|
||||
int minor,
|
||||
int enable_flag
|
||||
)
|
||||
{
|
||||
int mate;
|
||||
int is_a;
|
||||
unsigned int mask;
|
||||
unsigned int mate_mask;
|
||||
unsigned int pMC68681;
|
||||
unsigned int pMC68681_port;
|
||||
mc68681_context *pmc68681Context;
|
||||
mc68681_context *mateContext;
|
||||
|
||||
pMC68681 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
pmc68681Context = (mc68681_context *) Console_Port_Data[minor].pDeviceContext;
|
||||
mate = pmc68681Context->mate;
|
||||
|
||||
mask = 0;
|
||||
mate_mask = 0;
|
||||
|
||||
is_a = (pMC68681 == pMC68681_port);
|
||||
|
||||
/*
|
||||
* If there is a mate for this port, get its IMR mask.
|
||||
*/
|
||||
|
||||
if ( mate != -1 ) {
|
||||
mateContext = Console_Port_Data[mate].pDeviceContext;
|
||||
|
||||
if (mateContext)
|
||||
mate_mask = mateContext->imr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate this port's IMR mask and save it in the context area.
|
||||
*/
|
||||
|
||||
if ( Console_Port_Tbl[minor]->pDeviceFns->deviceOutputUsesInterrupts )
|
||||
mask = enable_flag;
|
||||
|
||||
pmc68681Context->imr = mask;
|
||||
|
||||
/*
|
||||
* Now return the full IMR value
|
||||
*/
|
||||
|
||||
if (is_a)
|
||||
return (mate_mask << 4) | mask;
|
||||
|
||||
return (mask << 4) | mate_mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* mc68681_enable_interrupts
|
||||
*
|
||||
* This function enables specific interrupt sources on the DUART.
|
||||
*/
|
||||
|
||||
MC68681_STATIC void mc68681_enable_interrupts(
|
||||
int minor,
|
||||
int imr_mask
|
||||
)
|
||||
{
|
||||
uint32_t pMC68681;
|
||||
setRegister_f setReg;
|
||||
|
||||
pMC68681 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Enable interrupts on RX and TX -- not break
|
||||
*/
|
||||
|
||||
(*setReg)(
|
||||
pMC68681,
|
||||
MC68681_INTERRUPT_MASK_REG,
|
||||
mc68681_build_imr(minor, imr_mask)
|
||||
);
|
||||
}
|
||||
124
bsps/shared/dev/serial/mc68681_baud.c
Normal file
124
bsps/shared/dev/serial/mc68681_baud.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* MC68681 Default Baud Rate Table
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <libchip/serial.h>
|
||||
#include <libchip/mc68681.h>
|
||||
|
||||
/* major index of 0 : ACR[7] = 0, X = 0 -- 68c681 only has these */
|
||||
/* major index of 1 : ACR[7] = 1, X = 0 -- 68c681 only has these */
|
||||
/* major index of 2 : ACR[7] = 0, X = 1 */
|
||||
/* major index of 3 : ACR[7] = 1, X = 1 */
|
||||
|
||||
/* mc68681_baud_table_t mc68681_baud_rate_table[4] = { */
|
||||
mc68681_baud_t mc68681_baud_rate_table[4][RTEMS_TERMIOS_NUMBER_BAUD_RATES] = {
|
||||
{ /* ACR[7] = 0, X = 0 */
|
||||
MC68681_BAUD_NOT_VALID, /* B0 */
|
||||
0x00, /* B50 */
|
||||
MC68681_BAUD_NOT_VALID, /* B75 */
|
||||
0x01, /* B110 */
|
||||
0x02, /* B134 */
|
||||
MC68681_BAUD_NOT_VALID, /* B150 */
|
||||
0x03, /* B200 */
|
||||
0x04, /* B300 */
|
||||
0x05, /* B600 */
|
||||
0x06, /* B1200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B1800 */
|
||||
0x08, /* B2400 */
|
||||
0x09, /* B4800 */
|
||||
0x0B, /* B9600 */
|
||||
MC68681_BAUD_NOT_VALID, /* B19200 */
|
||||
0x0C, /* B38400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B7200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B14400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B28800 */
|
||||
MC68681_BAUD_NOT_VALID, /* B57600 */
|
||||
MC68681_BAUD_NOT_VALID, /* B76800 */
|
||||
MC68681_BAUD_NOT_VALID, /* B115200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B230400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B460800 */
|
||||
MC68681_BAUD_NOT_VALID /* B921600 */
|
||||
},
|
||||
{ /* ACR[7] = 1, X = 0 */
|
||||
MC68681_BAUD_NOT_VALID, /* B0 */
|
||||
MC68681_BAUD_NOT_VALID, /* B50 */
|
||||
0x00, /* B75 */
|
||||
0x01, /* B110 */
|
||||
0x02, /* B134 */
|
||||
0x03, /* B150 */
|
||||
MC68681_BAUD_NOT_VALID, /* B200 */
|
||||
0x04, /* B300 */
|
||||
0x05, /* B600 */
|
||||
0x06, /* B1200 */
|
||||
0x0A, /* B1800 */
|
||||
0x08, /* B2400 */
|
||||
0x09, /* B4800 */
|
||||
0x0B, /* B9600 */
|
||||
0x0C, /* B19200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B38400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B7200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B14400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B28800 */
|
||||
MC68681_BAUD_NOT_VALID, /* B57600 */
|
||||
MC68681_BAUD_NOT_VALID, /* B76800 */
|
||||
MC68681_BAUD_NOT_VALID, /* B115200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B230400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B460800 */
|
||||
MC68681_BAUD_NOT_VALID /* B921600 */
|
||||
},
|
||||
{ /* ACR[7] = 0, X = 1 */
|
||||
MC68681_BAUD_NOT_VALID, /* B0 */
|
||||
MC68681_BAUD_NOT_VALID, /* B50 */
|
||||
0x00, /* B75 */
|
||||
0x01, /* B110 */
|
||||
0x02, /* B134 */
|
||||
0x03, /* B150 */
|
||||
MC68681_BAUD_NOT_VALID, /* B200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B300 */
|
||||
MC68681_BAUD_NOT_VALID, /* B600 */
|
||||
MC68681_BAUD_NOT_VALID, /* B1200 */
|
||||
0x0A, /* B1800 */
|
||||
MC68681_BAUD_NOT_VALID, /* B2400 */
|
||||
0x08, /* B4800 */
|
||||
0x0B, /* B9600 */
|
||||
0x0C, /* B19200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B38400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B7200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B14400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B28800 */
|
||||
0x07, /* B57600 */
|
||||
MC68681_BAUD_NOT_VALID, /* B76800 */
|
||||
0x08, /* B115200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B230400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B460800 */
|
||||
MC68681_BAUD_NOT_VALID /* B921600 */
|
||||
},
|
||||
{ /* ACR[7] = 1, X = 1 */
|
||||
MC68681_BAUD_NOT_VALID, /* B0 */
|
||||
0x00, /* B50 */
|
||||
MC68681_BAUD_NOT_VALID, /* B75 */
|
||||
0x01, /* B110 */
|
||||
0x02, /* B134 */
|
||||
MC68681_BAUD_NOT_VALID, /* B150 */
|
||||
0x03, /* B200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B300 */
|
||||
MC68681_BAUD_NOT_VALID, /* B600 */
|
||||
MC68681_BAUD_NOT_VALID, /* B1200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B1800 */
|
||||
MC68681_BAUD_NOT_VALID, /* B2400 */
|
||||
0x09, /* B4800 */
|
||||
0x0B, /* B9600 */
|
||||
MC68681_BAUD_NOT_VALID, /* B19200 */
|
||||
0x0C, /* B38400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B7200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B14400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B28800 */
|
||||
0x07, /* B57600 */
|
||||
MC68681_BAUD_NOT_VALID, /* B76800 */
|
||||
0x08, /* B115200 */
|
||||
MC68681_BAUD_NOT_VALID, /* B230400 */
|
||||
MC68681_BAUD_NOT_VALID, /* B460800 */
|
||||
MC68681_BAUD_NOT_VALID /* B921600 */
|
||||
},
|
||||
};
|
||||
323
bsps/shared/dev/serial/mc68681_p.h
Normal file
323
bsps/shared/dev/serial/mc68681_p.h
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1999.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifndef _MC68681_P_H_
|
||||
#define _MC68681_P_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define MC68681_STATIC to nothing while debugging so the entry points
|
||||
* will show up in the symbol table.
|
||||
*/
|
||||
|
||||
#define MC68681_STATIC
|
||||
|
||||
/* #define MC68681_STATIC static */
|
||||
|
||||
/*
|
||||
* mc68681 register offsets Read/Write Addresses
|
||||
*/
|
||||
|
||||
#define MC68681_MODE_REG_1A 0 /* MR1A-MR Prior to Read */
|
||||
#define MC68681_MODE_REG_2A 0 /* MR2A-MR After Read */
|
||||
|
||||
#define MC68681_COUNT_MODE_CURRENT_MSB 6 /* CTU */
|
||||
#define MC68681_COUNTER_TIMER_UPPER_REG 6 /* CTU */
|
||||
#define MC68681_COUNT_MODE_CURRENT_LSB 7 /* CTL */
|
||||
#define MC68681_COUNTER_TIMER_LOWER_REG 7 /* CTL */
|
||||
#define MC68681_INTERRUPT_VECTOR_REG 12 /* IVR */
|
||||
|
||||
#define MC68681_MODE_REG_1B 8 /* MR1B-MR Prior to Read */
|
||||
#define MC68681_MODE_REG_2B 8 /* MR2BA-MR After Read */
|
||||
|
||||
/*
|
||||
* mc68681 register offsets Read Only Addresses
|
||||
*/
|
||||
|
||||
#define MC68681_STATUS_REG_A 1 /* SRA */
|
||||
#define MC68681_MASK_ISR_REG 2 /* MISR */
|
||||
#define MC68681_RECEIVE_BUFFER_A 3 /* RHRA */
|
||||
#define MC68681_INPUT_PORT_CHANGE_REG 4 /* IPCR */
|
||||
#define MC68681_INTERRUPT_STATUS_REG 5 /* ISR */
|
||||
#define MC68681_STATUS_REG_B 9 /* SRB */
|
||||
#define MC68681_RECEIVE_BUFFER_B 11 /* RHRB */
|
||||
#define MC68681_INPUT_PORT 13 /* IP */
|
||||
#define MC68681_START_COUNT_CMD 14 /* SCC */
|
||||
#define MC68681_STOP_COUNT_CMD 15 /* STC */
|
||||
|
||||
/*
|
||||
* mc68681 register offsets Write Only Addresses
|
||||
*/
|
||||
|
||||
#define MC68681_CLOCK_SELECT_REG_A 1 /* CSRA */
|
||||
#define MC68681_COMMAND_REG_A 2 /* CRA */
|
||||
#define MC68681_TRANSMIT_BUFFER_A 3 /* THRA */
|
||||
#define MC68681_AUX_CTRL_REG 4 /* ACR */
|
||||
#define MC68681_INTERRUPT_MASK_REG 5 /* IMR */
|
||||
#define MC68681_CLOCK_SELECT_REG_B 9 /* CSRB */
|
||||
#define MC68681_COMMAND_REG_B 10 /* CRB */
|
||||
#define MC68681_TRANSMIT_BUFFER_B 11 /* THRB */
|
||||
#define MC68681_OUTPUT_PORT_CONFIG_REG 13 /* OPCR */
|
||||
#define MC68681_OUTPUT_PORT_SET_REG 14 /* SOPBC */
|
||||
#define MC68681_OUTPUT_PORT_RESET_BITS 15 /* COPBC */
|
||||
|
||||
/*
|
||||
* DUART Command Register Definitions:
|
||||
*
|
||||
* MC68681_COMMAND_REG_A,MC68681_COMMAND_REG_B
|
||||
*/
|
||||
|
||||
#define MC68681_MODE_REG_ENABLE_RX 0x01
|
||||
#define MC68681_MODE_REG_DISABLE_RX 0x02
|
||||
#define MC68681_MODE_REG_ENABLE_TX 0x04
|
||||
#define MC68681_MODE_REG_DISABLE_TX 0x08
|
||||
#define MC68681_MODE_REG_RESET_MR_PTR 0x10
|
||||
#define MC68681_MODE_REG_RESET_RX 0x20
|
||||
#define MC68681_MODE_REG_RESET_TX 0x30
|
||||
#define MC68681_MODE_REG_RESET_ERROR 0x40
|
||||
#define MC68681_MODE_REG_RESET_BREAK 0x50
|
||||
#define MC68681_MODE_REG_START_BREAK 0x60
|
||||
#define MC68681_MODE_REG_STOP_BREAK 0x70
|
||||
#define MC68681_MODE_REG_SET_RX_BRG 0x80
|
||||
#define MC68681_MODE_REG_CLEAR_RX_BRG 0x90
|
||||
#define MC68681_MODE_REG_SET_TX_BRG 0xa0
|
||||
#define MC68681_MODE_REG_CLEAR_TX_BRG 0xb0
|
||||
#define MC68681_MODE_REG_SET_STANDBY 0xc0
|
||||
#define MC68681_MODE_REG_SET_ACTIVE 0xd0
|
||||
|
||||
/*
|
||||
* Mode Register Definitions
|
||||
*
|
||||
* MC68681_MODE_REG_1A
|
||||
* MC68681_MODE_REG_1B
|
||||
*/
|
||||
|
||||
#define MC68681_5BIT_CHARS 0x00
|
||||
#define MC68681_6BIT_CHARS 0x01
|
||||
#define MC68681_7BIT_CHARS 0x02
|
||||
#define MC68681_8BIT_CHARS 0x03
|
||||
|
||||
#define MC68681_ODD_PARITY 0x00
|
||||
#define MC68681_EVEN_PARITY 0x04
|
||||
|
||||
#define MC68681_WITH_PARITY 0x00
|
||||
#define MC68681_FORCE_PARITY 0x08
|
||||
#define MC68681_NO_PARITY 0x10
|
||||
#define MC68681_MULTI_DROP 0x18
|
||||
|
||||
#define MC68681_ERR_MODE_CHAR 0x00
|
||||
#define MC68681_ERR_MODE_BLOCK 0x20
|
||||
|
||||
#define MC68681_RX_INTR_RX_READY 0x00
|
||||
#define MC68681_RX_INTR_FFULL 0x40
|
||||
|
||||
#define MC68681_NO_RX_RTS_CTL 0x00
|
||||
#define MC68681_RX_RTS_CTRL 0x80
|
||||
|
||||
/*
|
||||
* Mode Register Definitions
|
||||
*
|
||||
* MC68681_MODE_REG_2A
|
||||
* MC68681_MODE_REG_2B
|
||||
*/
|
||||
|
||||
#define MC68681_STOP_BIT_LENGTH__563 0x00
|
||||
#define MC68681_STOP_BIT_LENGTH__625 0x01
|
||||
#define MC68681_STOP_BIT_LENGTH__688 0x02
|
||||
#define MC68681_STOP_BIT_LENGTH__75 0x03
|
||||
#define MC68681_STOP_BIT_LENGTH__813 0x04
|
||||
#define MC68681_STOP_BIT_LENGTH__875 0x05
|
||||
#define MC68681_STOP_BIT_LENGTH__938 0x06
|
||||
#define MC68681_STOP_BIT_LENGTH_1 0x07
|
||||
#define MC68681_STOP_BIT_LENGTH_1_563 0x08
|
||||
#define MC68681_STOP_BIT_LENGTH_1_625 0x09
|
||||
#define MC68681_STOP_BIT_LENGTH_1_688 0x0a
|
||||
#define MC68681_STOP_BIT_LENGTH_1_75 0x0b
|
||||
#define MC68681_STOP_BIT_LENGTH_1_813 0x0c
|
||||
#define MC68681_STOP_BIT_LENGTH_1_875 0x0d
|
||||
#define MC68681_STOP_BIT_LENGTH_1_938 0x0e
|
||||
#define MC68681_STOP_BIT_LENGTH_2 0x0f
|
||||
|
||||
#define MC68681_CTS_ENABLE_TX 0x10
|
||||
#define MC68681_TX_RTS_CTRL 0x20
|
||||
|
||||
#define MC68681_CHANNEL_MODE_NORMAL 0x00
|
||||
#define MC68681_CHANNEL_MODE_ECHO 0x40
|
||||
#define MC68681_CHANNEL_MODE_LOCAL_LOOP 0x80
|
||||
#define MC68681_CHANNEL_MODE_REMOTE_LOOP 0xc0
|
||||
|
||||
/*
|
||||
* Status Register Definitions
|
||||
*
|
||||
* MC68681_STATUS_REG_A, MC68681_STATUS_REG_B
|
||||
*/
|
||||
|
||||
#define MC68681_RX_READY 0x01
|
||||
#define MC68681_FFULL 0x02
|
||||
#define MC68681_TX_READY 0x04
|
||||
#define MC68681_TX_EMPTY 0x08
|
||||
#define MC68681_OVERRUN_ERROR 0x10
|
||||
#define MC68681_PARITY_ERROR 0x20
|
||||
#define MC68681_FRAMING_ERROR 0x40
|
||||
#define MC68681_RECEIVED_BREAK 0x80
|
||||
|
||||
#define MC68681_RX_ERRORS \
|
||||
(MC68681_OVERRUN_ERROR|MC68681_PARITY_ERROR| \
|
||||
MC68681_FRAMING_ERROR|MC68681_RECEIVED_BREAK)
|
||||
|
||||
/*
|
||||
* Interupt Status Register Definitions.
|
||||
*
|
||||
* MC68681_INTERRUPT_STATUS_REG
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interupt Mask Register Definitions
|
||||
*
|
||||
* MC68681_INTERRUPT_MASK_REG
|
||||
*/
|
||||
|
||||
/* These are passed to mc68681_build_imr */
|
||||
#define MC68681_IR_TX_READY 0x01
|
||||
#define MC68681_IR_RX_READY 0x02
|
||||
#define MC68681_IR_BREAK 0x04
|
||||
#define MC68681_IMR_ENABLE_ALL 0x07
|
||||
#define MC68681_IMR_DISABLE_ALL 0x00
|
||||
#define MC68681_IMR_ENABLE_ALL_EXCEPT_TX 0x06
|
||||
|
||||
#define MC68681_IR_TX_READY_A 0x01
|
||||
#define MC68681_IR_RX_READY_A 0x02
|
||||
#define MC68681_IR_BREAK_A 0x04
|
||||
#define MC68681_IR_COUNTER_READY 0x08
|
||||
#define MC68681_IR_TX_READY_B 0x10
|
||||
#define MC68681_IR_RX_READY_B 0x20
|
||||
#define MC68681_IR_BREAK_B 0x40
|
||||
#define MC68681_IR_INPUT_PORT_CHANGE 0x80
|
||||
|
||||
/*
|
||||
* Status Register Definitions.
|
||||
*
|
||||
* MC68681_STATUS_REG_A,MC68681_STATUS_REG_B
|
||||
*/
|
||||
|
||||
#define MC68681_STATUS_RXRDY 0x01
|
||||
#define MC68681_STATUS_FFULL 0x02
|
||||
#define MC68681_STATUS_TXRDY 0x04
|
||||
#define MC68681_STATUS_TXEMT 0x08
|
||||
#define MC68681_STATUS_OVERRUN_ERROR 0x10
|
||||
#define MC68681_STATUS_PARITY_ERROR 0x20
|
||||
#define MC68681_STATUS_FRAMING_ERROR 0x40
|
||||
#define MC68681_STATUS_RECEIVED_BREAK 0x80
|
||||
|
||||
/*
|
||||
* Definitions for the Interrupt Vector Register:
|
||||
*
|
||||
* MC68681_INTERRUPT_VECTOR_REG
|
||||
*/
|
||||
|
||||
#define MC68681_INTERRUPT_VECTOR_INIT 0x0f
|
||||
|
||||
/*
|
||||
* Definitions for the Auxiliary Control Register
|
||||
*
|
||||
* MC68681_AUX_CTRL_REG
|
||||
*/
|
||||
|
||||
#define MC68681_AUX_BRG_SET1 0x00
|
||||
#define MC68681_AUX_BRG_SET2 0x80
|
||||
|
||||
/*
|
||||
* Per chip context control
|
||||
*/
|
||||
|
||||
typedef struct _mc68681_context
|
||||
{
|
||||
int mate;
|
||||
unsigned char imr;
|
||||
} mc68681_context;
|
||||
|
||||
/*
|
||||
* Driver functions
|
||||
*/
|
||||
MC68681_STATIC void mc68681_initialize_context(
|
||||
int minor,
|
||||
mc68681_context *pmc68681Context
|
||||
);
|
||||
|
||||
MC68681_STATIC bool mc68681_probe(int minor);
|
||||
|
||||
MC68681_STATIC int mc68681_set_attributes(
|
||||
int minor,
|
||||
const struct termios *t
|
||||
);
|
||||
|
||||
MC68681_STATIC void mc68681_init(int minor);
|
||||
|
||||
MC68681_STATIC int mc68681_open(
|
||||
int major,
|
||||
int minor,
|
||||
void * arg
|
||||
);
|
||||
|
||||
MC68681_STATIC int mc68681_close(
|
||||
int major,
|
||||
int minor,
|
||||
void * arg
|
||||
);
|
||||
|
||||
MC68681_STATIC void mc68681_write_polled(
|
||||
int minor,
|
||||
char cChar
|
||||
);
|
||||
|
||||
MC68681_STATIC void mc68681_initialize_interrupts(int minor);
|
||||
|
||||
MC68681_STATIC ssize_t mc68681_write_support_int(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
);
|
||||
|
||||
MC68681_STATIC ssize_t mc68681_write_support_polled(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
);
|
||||
|
||||
MC68681_STATIC int mc68681_inbyte_nonblocking_polled(
|
||||
int minor
|
||||
);
|
||||
|
||||
MC68681_STATIC unsigned int mc68681_build_imr(
|
||||
int minor,
|
||||
int enable_flag
|
||||
);
|
||||
|
||||
MC68681_STATIC void mc68681_process(
|
||||
int minor
|
||||
);
|
||||
|
||||
MC68681_STATIC void mc68681_enable_interrupts(
|
||||
int minor,
|
||||
int imr_mask
|
||||
);
|
||||
|
||||
MC68681_STATIC rtems_isr mc68681_isr(
|
||||
rtems_vector_number vector
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MC68681_P_H_ */
|
||||
61
bsps/shared/dev/serial/mc68681_reg.c
Normal file
61
bsps/shared/dev/serial/mc68681_reg.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the mc68681 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are only byte-aligned (no address gaps)
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#include <libchip/serial.h>
|
||||
#include <libchip/mc68681.h>
|
||||
|
||||
#ifndef _MC68681_MULTIPLIER
|
||||
#define _MC68681_MULTIPLIER 1
|
||||
#define _MC68681_NAME(_X) _X
|
||||
#define _MC68681_TYPE uint8_t
|
||||
#endif
|
||||
|
||||
#define CALCULATE_REGISTER_ADDRESS( _base, _reg ) \
|
||||
(_MC68681_TYPE *)((_base) + ((_reg) * _MC68681_MULTIPLIER ))
|
||||
|
||||
/*
|
||||
* MC68681 Get Register Routine
|
||||
*/
|
||||
|
||||
uint8_t _MC68681_NAME(mc68681_get_register)(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum
|
||||
)
|
||||
{
|
||||
_MC68681_TYPE *port;
|
||||
|
||||
port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
|
||||
|
||||
return *port;
|
||||
}
|
||||
|
||||
/*
|
||||
* MC68681 Set Register Routine
|
||||
*/
|
||||
|
||||
void _MC68681_NAME(mc68681_set_register)(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum,
|
||||
uint8_t ucData
|
||||
)
|
||||
{
|
||||
_MC68681_TYPE *port;
|
||||
|
||||
port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
|
||||
|
||||
*port = ucData;
|
||||
}
|
||||
20
bsps/shared/dev/serial/mc68681_reg2.c
Normal file
20
bsps/shared/dev/serial/mc68681_reg2.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the mc68681 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are on 16-bit boundaries
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define _MC68681_MULTIPLIER 2
|
||||
#define _MC68681_NAME(_X) _X##_2
|
||||
#define _MC68681_TYPE uint8_t
|
||||
|
||||
#include "mc68681_reg.c"
|
||||
20
bsps/shared/dev/serial/mc68681_reg4.c
Normal file
20
bsps/shared/dev/serial/mc68681_reg4.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the mc68681 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are on 32-bit boundaries
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define _MC68681_MULTIPLIER 4
|
||||
#define _MC68681_NAME(_X) _X##_4
|
||||
#define _MC68681_TYPE uint8_t
|
||||
|
||||
#include "mc68681_reg.c"
|
||||
20
bsps/shared/dev/serial/mc68681_reg8.c
Normal file
20
bsps/shared/dev/serial/mc68681_reg8.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the mc68681 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
* + registers are on 64-bit boundaries
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define _MC68681_MULTIPLIER 8
|
||||
#define _MC68681_NAME(_X) _X##_8
|
||||
#define _MC68681_TYPE uint8_t
|
||||
|
||||
#include "mc68681_reg.c"
|
||||
814
bsps/shared/dev/serial/ns16550-context.c
Normal file
814
bsps/shared/dev/serial/ns16550-context.c
Normal file
@@ -0,0 +1,814 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This file contains the TTY driver for the National Semiconductor NS16550.
|
||||
*
|
||||
* This part is widely cloned and second sourced. It is found in a number
|
||||
* of "Super IO" controllers.
|
||||
*
|
||||
* This driver uses the termios pseudo driver.
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPYRIGHT (c) 1998 by Radstone Technology
|
||||
*
|
||||
* THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
|
||||
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
|
||||
* AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
|
||||
*
|
||||
* You are hereby granted permission to use, copy, modify, and distribute
|
||||
* this file, provided that this notice, plus the above copyright notice
|
||||
* and disclaimer, appears in all copies. Radstone Technology will provide
|
||||
* no support for this code.
|
||||
*
|
||||
* COPYRIGHT (c) 1989-2012.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
#include <bsp.h>
|
||||
|
||||
#include <libchip/ns16550.h>
|
||||
#include <libchip/ns16550_p.h>
|
||||
|
||||
#if defined(BSP_FEATURE_IRQ_EXTENSION)
|
||||
#include <bsp/irq.h>
|
||||
#elif defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
#include <bsp/irq.h>
|
||||
#elif defined(__PPC__) || defined(__i386__)
|
||||
#include <bsp/irq.h>
|
||||
#define BSP_FEATURE_IRQ_LEGACY
|
||||
#ifdef BSP_SHARED_HANDLER_SUPPORT
|
||||
#define BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static uint32_t NS16550_GetBaudDivisor(ns16550_context *ctx, uint32_t baud)
|
||||
{
|
||||
uint32_t clock = ctx->clock;
|
||||
uint32_t baudDivisor = (clock != 0 ? clock : 115200) / (baud * 16);
|
||||
|
||||
if (ctx->has_fractional_divider_register) {
|
||||
uint32_t fractionalDivider = 0x10;
|
||||
uint32_t err = baud;
|
||||
uint32_t mulVal;
|
||||
uint32_t divAddVal;
|
||||
|
||||
clock /= 16 * baudDivisor;
|
||||
for (mulVal = 1; mulVal < 16; ++mulVal) {
|
||||
for (divAddVal = 0; divAddVal < mulVal; ++divAddVal) {
|
||||
uint32_t actual = (mulVal * clock) / (mulVal + divAddVal);
|
||||
uint32_t newErr = actual > baud ? actual - baud : baud - actual;
|
||||
|
||||
if (newErr < err) {
|
||||
err = newErr;
|
||||
fractionalDivider = (mulVal << 4) | divAddVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*ctx->set_reg)(
|
||||
ctx->port,
|
||||
NS16550_FRACTIONAL_DIVIDER,
|
||||
fractionalDivider
|
||||
);
|
||||
}
|
||||
|
||||
return baudDivisor;
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_enable_interrupts
|
||||
*
|
||||
* This routine initializes the port to have the specified interrupts masked.
|
||||
*/
|
||||
static void ns16550_enable_interrupts(
|
||||
ns16550_context *ctx,
|
||||
int mask
|
||||
)
|
||||
{
|
||||
(*ctx->set_reg)(ctx->port, NS16550_INTERRUPT_ENABLE, mask);
|
||||
}
|
||||
|
||||
static void ns16550_clear_and_set_interrupts(
|
||||
ns16550_context *ctx,
|
||||
uint8_t clear,
|
||||
uint8_t set
|
||||
)
|
||||
{
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
ns16550_get_reg get_reg = ctx->get_reg;
|
||||
ns16550_set_reg set_reg = ctx->set_reg;
|
||||
uintptr_t port = ctx->port;
|
||||
uint8_t val;
|
||||
|
||||
rtems_termios_device_lock_acquire(&ctx->base, &lock_context);
|
||||
val = (*get_reg)(port, NS16550_INTERRUPT_ENABLE);
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
(*set_reg)(port, NS16550_INTERRUPT_ENABLE, val);
|
||||
rtems_termios_device_lock_release(&ctx->base, &lock_context);
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_probe
|
||||
*/
|
||||
|
||||
bool ns16550_probe(rtems_termios_device_context *base)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
uintptr_t pNS16550;
|
||||
uint8_t ucDataByte;
|
||||
uint32_t ulBaudDivisor;
|
||||
ns16550_set_reg setReg;
|
||||
ns16550_get_reg getReg;
|
||||
|
||||
ctx->modem_control = SP_MODEM_IRQ;
|
||||
|
||||
pNS16550 = ctx->port;
|
||||
setReg = ctx->set_reg;
|
||||
getReg = ctx->get_reg;
|
||||
|
||||
/* Clear the divisor latch, clear all interrupt enables,
|
||||
* and reset and
|
||||
* disable the FIFO's.
|
||||
*/
|
||||
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, 0x0);
|
||||
ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR );
|
||||
|
||||
/* Set the divisor latch and set the baud rate. */
|
||||
|
||||
ulBaudDivisor = NS16550_GetBaudDivisor(ctx, ctx->initial_baud);
|
||||
ctx->baud_divisor = ulBaudDivisor;
|
||||
ucDataByte = SP_LINE_DLAB;
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
|
||||
|
||||
/* XXX */
|
||||
(*setReg)(pNS16550,NS16550_TRANSMIT_BUFFER,(uint8_t)(ulBaudDivisor & 0xffU));
|
||||
(*setReg)(
|
||||
pNS16550,NS16550_INTERRUPT_ENABLE,
|
||||
(uint8_t)(( ulBaudDivisor >> 8 ) & 0xffU )
|
||||
);
|
||||
|
||||
/* Clear the divisor latch and set the character size to eight bits */
|
||||
/* with one stop bit and no parity checking. */
|
||||
ucDataByte = EIGHT_BITS;
|
||||
ctx->line_control = ucDataByte;
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
|
||||
|
||||
/* Enable and reset transmit and receive FIFOs. TJA */
|
||||
ucDataByte = SP_FIFO_ENABLE;
|
||||
(*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
|
||||
|
||||
ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
|
||||
(*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
|
||||
|
||||
ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
|
||||
|
||||
/* Set data terminal ready. */
|
||||
/* And open interrupt tristate line */
|
||||
(*setReg)(pNS16550, NS16550_MODEM_CONTROL,ctx->modem_control);
|
||||
|
||||
(*getReg)(pNS16550, NS16550_LINE_STATUS );
|
||||
(*getReg)(pNS16550, NS16550_RECEIVE_BUFFER );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t ns16550_write_to_fifo(
|
||||
const ns16550_context *ctx,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
uintptr_t port = ctx->port;
|
||||
ns16550_set_reg set = ctx->set_reg;
|
||||
size_t out = len > SP_FIFO_SIZE ? SP_FIFO_SIZE : len;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < out; ++i) {
|
||||
(*set)(port, NS16550_TRANSMIT_BUFFER, buf[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Process interrupt.
|
||||
*/
|
||||
static void ns16550_isr(void *arg)
|
||||
{
|
||||
rtems_termios_tty *tty = arg;
|
||||
ns16550_context *ctx = rtems_termios_get_device_context(tty);
|
||||
uintptr_t port = ctx->port;
|
||||
ns16550_get_reg get = ctx->get_reg;
|
||||
int i = 0;
|
||||
char buf [SP_FIFO_SIZE];
|
||||
|
||||
/* Iterate until no more interrupts are pending */
|
||||
do {
|
||||
/* Fetch received characters */
|
||||
for (i = 0; i < SP_FIFO_SIZE; ++i) {
|
||||
if ((get( port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
|
||||
buf [i] = (char) get(port, NS16550_RECEIVE_BUFFER);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enqueue fetched characters */
|
||||
rtems_termios_enqueue_raw_characters(tty, buf, i);
|
||||
|
||||
/* Do transmit */
|
||||
if (ctx->out_total > 0
|
||||
&& (get(port, NS16550_LINE_STATUS) & SP_LSR_THOLD) != 0) {
|
||||
size_t current = ctx->out_current;
|
||||
|
||||
ctx->out_buf += current;
|
||||
ctx->out_remaining -= current;
|
||||
|
||||
if (ctx->out_remaining > 0) {
|
||||
ctx->out_current =
|
||||
ns16550_write_to_fifo(ctx, ctx->out_buf, ctx->out_remaining);
|
||||
} else {
|
||||
rtems_termios_dequeue_characters(tty, ctx->out_total);
|
||||
}
|
||||
}
|
||||
} while ((get( port, NS16550_INTERRUPT_ID) & SP_IID_0) == 0);
|
||||
}
|
||||
|
||||
static void ns16550_isr_task(void *arg)
|
||||
{
|
||||
rtems_termios_tty *tty = arg;
|
||||
ns16550_context *ctx = rtems_termios_get_device_context(tty);
|
||||
uint8_t status = (*ctx->get_reg)(ctx->port, NS16550_LINE_STATUS);
|
||||
|
||||
if ((status & SP_LSR_RDY) != 0) {
|
||||
ns16550_clear_and_set_interrupts(ctx, SP_INT_RX_ENABLE, 0);
|
||||
rtems_termios_rxirq_occured(tty);
|
||||
}
|
||||
|
||||
if (ctx->out_total > 0 && (status & SP_LSR_THOLD) != 0) {
|
||||
size_t current = ctx->out_current;
|
||||
|
||||
ctx->out_buf += current;
|
||||
ctx->out_remaining -= current;
|
||||
|
||||
if (ctx->out_remaining > 0) {
|
||||
ctx->out_current =
|
||||
ns16550_write_to_fifo(ctx, ctx->out_buf, ctx->out_remaining);
|
||||
} else {
|
||||
size_t done = ctx->out_total;
|
||||
|
||||
ctx->out_total = 0;
|
||||
ns16550_clear_and_set_interrupts(ctx, SP_INT_TX_ENABLE, 0);
|
||||
rtems_termios_dequeue_characters(tty, done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ns16550_read_task(rtems_termios_device_context *base)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
uintptr_t port = ctx->port;
|
||||
ns16550_get_reg get = ctx->get_reg;
|
||||
char buf[SP_FIFO_SIZE];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SP_FIFO_SIZE; ++i) {
|
||||
if ((get(port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
|
||||
buf[i] = (char) get(port, NS16550_RECEIVE_BUFFER);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rtems_termios_enqueue_raw_characters(ctx->tty, buf, i);
|
||||
ns16550_clear_and_set_interrupts(ctx, 0, SP_INT_RX_ENABLE);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_initialize_interrupts
|
||||
*
|
||||
* This routine initializes the port to operate in interrupt driver mode.
|
||||
*/
|
||||
static void ns16550_initialize_interrupts(
|
||||
struct rtems_termios_tty *tty,
|
||||
ns16550_context *ctx,
|
||||
void (*isr)(void *)
|
||||
)
|
||||
{
|
||||
#ifdef BSP_FEATURE_IRQ_EXTENSION
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
sc = rtems_interrupt_handler_install(
|
||||
ctx->irq,
|
||||
"NS16550",
|
||||
RTEMS_INTERRUPT_SHARED,
|
||||
isr,
|
||||
tty
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
/* FIXME */
|
||||
printk( "%s: Error: Install interrupt handler\n", __func__);
|
||||
rtems_fatal_error_occurred( 0xdeadbeef);
|
||||
}
|
||||
}
|
||||
#elif defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
{
|
||||
int rv = 0;
|
||||
#ifdef BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
|
||||
rtems_irq_connect_data cd = {
|
||||
ctx->irq,
|
||||
isr,
|
||||
tty,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
rv = BSP_install_rtems_shared_irq_handler( &cd);
|
||||
#else
|
||||
rtems_irq_connect_data cd = {
|
||||
ctx->irq,
|
||||
isr,
|
||||
tty,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
rv = BSP_install_rtems_irq_handler( &cd);
|
||||
#endif
|
||||
if (rv == 0) {
|
||||
/* FIXME */
|
||||
printk( "%s: Error: Install interrupt handler\n", __func__);
|
||||
rtems_fatal_error_occurred( 0xdeadbeef);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_open
|
||||
*/
|
||||
|
||||
static bool ns16550_open(
|
||||
struct rtems_termios_tty *tty,
|
||||
rtems_termios_device_context *base,
|
||||
struct termios *term,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
|
||||
ctx->tty = tty;
|
||||
|
||||
/* Set initial baud */
|
||||
rtems_termios_set_initial_baud(tty, ctx->initial_baud);
|
||||
|
||||
if (tty->handler.mode == TERMIOS_IRQ_DRIVEN) {
|
||||
ns16550_initialize_interrupts(tty, ctx, ns16550_isr);
|
||||
ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
|
||||
} else if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
|
||||
ns16550_initialize_interrupts(tty, ctx, ns16550_isr_task);
|
||||
ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ns16550_cleanup_interrupts(
|
||||
struct rtems_termios_tty *tty,
|
||||
ns16550_context *ctx,
|
||||
void (*isr)(void *)
|
||||
)
|
||||
{
|
||||
#if defined(BSP_FEATURE_IRQ_EXTENSION)
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
sc = rtems_interrupt_handler_remove(
|
||||
ctx->irq,
|
||||
isr,
|
||||
tty
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
/* FIXME */
|
||||
printk("%s: Error: Remove interrupt handler\n", __func__);
|
||||
rtems_fatal_error_occurred(0xdeadbeef);
|
||||
}
|
||||
#elif defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
int rv = 0;
|
||||
rtems_irq_connect_data cd = {
|
||||
.name = ctx->irq,
|
||||
.hdl = isr,
|
||||
.handle = tty
|
||||
};
|
||||
rv = BSP_remove_rtems_irq_handler(&cd);
|
||||
if (rv == 0) {
|
||||
/* FIXME */
|
||||
printk("%s: Error: Remove interrupt handler\n", __func__);
|
||||
rtems_fatal_error_occurred(0xdeadbeef);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_close
|
||||
*/
|
||||
|
||||
static void ns16550_close(
|
||||
struct rtems_termios_tty *tty,
|
||||
rtems_termios_device_context *base,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
|
||||
ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
|
||||
|
||||
if (tty->handler.mode == TERMIOS_IRQ_DRIVEN) {
|
||||
ns16550_cleanup_interrupts(tty, ctx, ns16550_isr);
|
||||
} else if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
|
||||
ns16550_cleanup_interrupts(tty, ctx, ns16550_isr_task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Polled write for NS16550.
|
||||
*/
|
||||
void ns16550_polled_putchar(rtems_termios_device_context *base, char out)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
uintptr_t port = ctx->port;
|
||||
ns16550_get_reg get = ctx->get_reg;
|
||||
ns16550_set_reg set = ctx->set_reg;
|
||||
uint32_t status = 0;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
|
||||
/* Save port interrupt mask */
|
||||
uint32_t interrupt_mask = get( port, NS16550_INTERRUPT_ENABLE);
|
||||
|
||||
/* Disable port interrupts */
|
||||
ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
|
||||
|
||||
while (true) {
|
||||
/* Try to transmit the character in a critical section */
|
||||
rtems_termios_device_lock_acquire(&ctx->base, &lock_context);
|
||||
|
||||
/* Read the transmitter holding register and check it */
|
||||
status = get( port, NS16550_LINE_STATUS);
|
||||
if ((status & SP_LSR_THOLD) != 0) {
|
||||
/* Transmit character */
|
||||
set( port, NS16550_TRANSMIT_BUFFER, out);
|
||||
|
||||
/* Finished */
|
||||
rtems_termios_device_lock_release(&ctx->base, &lock_context);
|
||||
break;
|
||||
} else {
|
||||
rtems_termios_device_lock_release(&ctx->base, &lock_context);
|
||||
}
|
||||
|
||||
/* Wait for transmitter holding register to be empty */
|
||||
do {
|
||||
status = get( port, NS16550_LINE_STATUS);
|
||||
} while ((status & SP_LSR_THOLD) == 0);
|
||||
}
|
||||
|
||||
/* Restore port interrupt mask */
|
||||
set( port, NS16550_INTERRUPT_ENABLE, interrupt_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* These routines provide control of the RTS and DTR lines
|
||||
*/
|
||||
|
||||
/*
|
||||
* ns16550_assert_RTS
|
||||
*/
|
||||
|
||||
static void ns16550_assert_RTS(rtems_termios_device_context *base)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
|
||||
/*
|
||||
* Assert RTS
|
||||
*/
|
||||
rtems_termios_device_lock_acquire(base, &lock_context);
|
||||
ctx->modem_control |= SP_MODEM_RTS;
|
||||
(*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL, ctx->modem_control);
|
||||
rtems_termios_device_lock_release(base, &lock_context);
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_negate_RTS
|
||||
*/
|
||||
|
||||
static void ns16550_negate_RTS(rtems_termios_device_context *base)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
|
||||
/*
|
||||
* Negate RTS
|
||||
*/
|
||||
rtems_termios_device_lock_acquire(base, &lock_context);
|
||||
ctx->modem_control &= ~SP_MODEM_RTS;
|
||||
(*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL, ctx->modem_control);
|
||||
rtems_termios_device_lock_release(base, &lock_context);
|
||||
}
|
||||
|
||||
/*
|
||||
* These flow control routines utilise a connection from the local DTR
|
||||
* line to the remote CTS line
|
||||
*/
|
||||
|
||||
/*
|
||||
* ns16550_assert_DTR
|
||||
*/
|
||||
|
||||
static void ns16550_assert_DTR(rtems_termios_device_context *base)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
|
||||
/*
|
||||
* Assert DTR
|
||||
*/
|
||||
rtems_termios_device_lock_acquire(base, &lock_context);
|
||||
ctx->modem_control |= SP_MODEM_DTR;
|
||||
(*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL, ctx->modem_control);
|
||||
rtems_termios_device_lock_release(base, &lock_context);
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_negate_DTR
|
||||
*/
|
||||
|
||||
static void ns16550_negate_DTR(rtems_termios_device_context *base)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
|
||||
/*
|
||||
* Negate DTR
|
||||
*/
|
||||
rtems_termios_device_lock_acquire(base, &lock_context);
|
||||
ctx->modem_control &=~SP_MODEM_DTR;
|
||||
(*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL,ctx->modem_control);
|
||||
rtems_termios_device_lock_release(base, &lock_context);
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_set_attributes
|
||||
*
|
||||
* This function sets the channel to reflect the requested termios
|
||||
* port settings.
|
||||
*/
|
||||
|
||||
static bool ns16550_set_attributes(
|
||||
rtems_termios_device_context *base,
|
||||
const struct termios *t
|
||||
)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
uint32_t pNS16550;
|
||||
uint32_t ulBaudDivisor;
|
||||
uint8_t ucLineControl;
|
||||
uint32_t baud_requested;
|
||||
ns16550_set_reg setReg;
|
||||
|
||||
pNS16550 = ctx->port;
|
||||
setReg = ctx->set_reg;
|
||||
|
||||
/*
|
||||
* Calculate the baud rate divisor
|
||||
*
|
||||
* Assert ensures there is no division by 0.
|
||||
*/
|
||||
|
||||
baud_requested = rtems_termios_baud_to_number(t->c_ospeed);
|
||||
_Assert( baud_requested != 0 );
|
||||
|
||||
ulBaudDivisor = NS16550_GetBaudDivisor(ctx, baud_requested);
|
||||
|
||||
ucLineControl = 0;
|
||||
|
||||
/*
|
||||
* Parity
|
||||
*/
|
||||
|
||||
if (t->c_cflag & PARENB) {
|
||||
ucLineControl |= SP_LINE_PAR;
|
||||
if (!(t->c_cflag & PARODD))
|
||||
ucLineControl |= SP_LINE_ODD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Character Size
|
||||
*/
|
||||
|
||||
if (t->c_cflag & CSIZE) {
|
||||
switch (t->c_cflag & CSIZE) {
|
||||
case CS5: ucLineControl |= FIVE_BITS; break;
|
||||
case CS6: ucLineControl |= SIX_BITS; break;
|
||||
case CS7: ucLineControl |= SEVEN_BITS; break;
|
||||
case CS8: ucLineControl |= EIGHT_BITS; break;
|
||||
}
|
||||
} else {
|
||||
ucLineControl |= EIGHT_BITS; /* default to 9600,8,N,1 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop Bits
|
||||
*/
|
||||
|
||||
if (t->c_cflag & CSTOPB) {
|
||||
ucLineControl |= SP_LINE_STOP; /* 2 stop bits */
|
||||
} else {
|
||||
; /* 1 stop bit */
|
||||
}
|
||||
|
||||
/*
|
||||
* Now actually set the chip
|
||||
*/
|
||||
|
||||
if (ulBaudDivisor != ctx->baud_divisor || ucLineControl != ctx->line_control) {
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
|
||||
ctx->baud_divisor = ulBaudDivisor;
|
||||
ctx->line_control = ucLineControl;
|
||||
|
||||
rtems_termios_device_lock_acquire(base, &lock_context);
|
||||
|
||||
/*
|
||||
* Set the baud rate
|
||||
*
|
||||
* NOTE: When the Divisor Latch Access Bit (DLAB) is set to 1,
|
||||
* the transmit buffer and interrupt enable registers
|
||||
* turn into the LSB and MSB divisor latch registers.
|
||||
*/
|
||||
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, SP_LINE_DLAB);
|
||||
(*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, ulBaudDivisor&0xff);
|
||||
(*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff);
|
||||
|
||||
/*
|
||||
* Now write the line control
|
||||
*/
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
|
||||
|
||||
rtems_termios_device_lock_release(base, &lock_context);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmits up to @a len characters from @a buf.
|
||||
*
|
||||
* This routine is invoked either from task context with disabled interrupts to
|
||||
* start a new transmission process with exactly one character in case of an
|
||||
* idle output state or from the interrupt handler to refill the transmitter.
|
||||
*
|
||||
* Returns always zero.
|
||||
*/
|
||||
static void ns16550_write_support_int(
|
||||
rtems_termios_device_context *base,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
|
||||
ctx->out_total = len;
|
||||
|
||||
if (len > 0) {
|
||||
ctx->out_remaining = len;
|
||||
ctx->out_buf = buf;
|
||||
ctx->out_current = ns16550_write_to_fifo(ctx, buf, len);
|
||||
|
||||
ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR);
|
||||
} else {
|
||||
ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
|
||||
}
|
||||
}
|
||||
|
||||
static void ns16550_write_support_task(
|
||||
rtems_termios_device_context *base,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
|
||||
ctx->out_total = len;
|
||||
|
||||
if (len > 0) {
|
||||
ctx->out_remaining = len;
|
||||
ctx->out_buf = buf;
|
||||
ctx->out_current = ns16550_write_to_fifo(ctx, buf, len);
|
||||
|
||||
ns16550_clear_and_set_interrupts(ctx, 0, SP_INT_TX_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_write_support_polled
|
||||
*
|
||||
* Console Termios output entry point.
|
||||
*
|
||||
*/
|
||||
|
||||
static void ns16550_write_support_polled(
|
||||
rtems_termios_device_context *base,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
size_t nwrite = 0;
|
||||
|
||||
/*
|
||||
* poll each byte in the string out of the port.
|
||||
*/
|
||||
while (nwrite < len) {
|
||||
/*
|
||||
* transmit character
|
||||
*/
|
||||
ns16550_polled_putchar(base, *buf++);
|
||||
nwrite++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Debug gets() support
|
||||
*/
|
||||
int ns16550_polled_getchar(rtems_termios_device_context *base)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
uint32_t pNS16550;
|
||||
unsigned char ucLineStatus;
|
||||
uint8_t cChar;
|
||||
ns16550_get_reg getReg;
|
||||
|
||||
pNS16550 = ctx->port;
|
||||
getReg = ctx->get_reg;
|
||||
|
||||
ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
|
||||
if (ucLineStatus & SP_LSR_RDY) {
|
||||
cChar = (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER);
|
||||
return (int)cChar;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flow control is only supported when using interrupts
|
||||
*/
|
||||
|
||||
const rtems_termios_device_flow ns16550_flow_rtscts = {
|
||||
.stop_remote_tx = ns16550_negate_RTS,
|
||||
.start_remote_tx = ns16550_assert_RTS
|
||||
};
|
||||
|
||||
const rtems_termios_device_flow ns16550_flow_dtrcts = {
|
||||
.stop_remote_tx = ns16550_negate_DTR,
|
||||
.start_remote_tx = ns16550_assert_DTR
|
||||
};
|
||||
|
||||
const rtems_termios_device_handler ns16550_handler_interrupt = {
|
||||
.first_open = ns16550_open,
|
||||
.last_close = ns16550_close,
|
||||
.poll_read = NULL,
|
||||
.write = ns16550_write_support_int,
|
||||
.set_attributes = ns16550_set_attributes,
|
||||
.mode = TERMIOS_IRQ_DRIVEN
|
||||
};
|
||||
|
||||
const rtems_termios_device_handler ns16550_handler_polled = {
|
||||
.first_open = ns16550_open,
|
||||
.last_close = ns16550_close,
|
||||
.poll_read = ns16550_polled_getchar,
|
||||
.write = ns16550_write_support_polled,
|
||||
.set_attributes = ns16550_set_attributes,
|
||||
.mode = TERMIOS_POLLED
|
||||
};
|
||||
|
||||
const rtems_termios_device_handler ns16550_handler_task = {
|
||||
.first_open = ns16550_open,
|
||||
.last_close = ns16550_close,
|
||||
.poll_read = ns16550_read_task,
|
||||
.write = ns16550_write_support_task,
|
||||
.set_attributes = ns16550_set_attributes,
|
||||
.mode = TERMIOS_TASK_DRIVEN
|
||||
};
|
||||
875
bsps/shared/dev/serial/ns16550.c
Normal file
875
bsps/shared/dev/serial/ns16550.c
Normal file
@@ -0,0 +1,875 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This file contains the TTY driver for the National Semiconductor NS16550.
|
||||
*
|
||||
* This part is widely cloned and second sourced. It is found in a number
|
||||
* of "Super IO" controllers.
|
||||
*
|
||||
* This driver uses the termios pseudo driver.
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPYRIGHT (c) 1998 by Radstone Technology
|
||||
*
|
||||
* THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
|
||||
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
|
||||
* AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
|
||||
*
|
||||
* You are hereby granted permission to use, copy, modify, and distribute
|
||||
* this file, provided that this notice, plus the above copyright notice
|
||||
* and disclaimer, appears in all copies. Radstone Technology will provide
|
||||
* no support for this code.
|
||||
*
|
||||
* COPYRIGHT (c) 1989-2012.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/ringbuf.h>
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/termiostypes.h>
|
||||
|
||||
#include <libchip/serial.h>
|
||||
#include <libchip/sersupp.h>
|
||||
|
||||
#include <bsp.h>
|
||||
|
||||
#include <libchip/ns16550_p.h>
|
||||
#include <libchip/ns16550.h>
|
||||
|
||||
#if defined(BSP_FEATURE_IRQ_EXTENSION)
|
||||
#include <bsp/irq.h>
|
||||
#elif defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
#include <bsp/irq.h>
|
||||
#elif defined(__PPC__) || defined(__i386__)
|
||||
#include <bsp/irq.h>
|
||||
#define BSP_FEATURE_IRQ_LEGACY
|
||||
#ifdef BSP_SHARED_HANDLER_SUPPORT
|
||||
#define BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint8_t ucModemCtrl;
|
||||
int transmitFifoChars;
|
||||
} NS16550Context;
|
||||
|
||||
/*
|
||||
* Driver functions
|
||||
*/
|
||||
|
||||
NS16550_STATIC void ns16550_init(int minor);
|
||||
|
||||
NS16550_STATIC int ns16550_open(
|
||||
int major,
|
||||
int minor,
|
||||
void * arg
|
||||
);
|
||||
|
||||
NS16550_STATIC int ns16550_close(
|
||||
int major,
|
||||
int minor,
|
||||
void * arg
|
||||
);
|
||||
|
||||
NS16550_STATIC void ns16550_write_polled(
|
||||
int minor,
|
||||
char cChar
|
||||
);
|
||||
|
||||
NS16550_STATIC int ns16550_assert_RTS(
|
||||
int minor
|
||||
);
|
||||
|
||||
NS16550_STATIC int ns16550_negate_RTS(
|
||||
int minor
|
||||
);
|
||||
|
||||
NS16550_STATIC int ns16550_assert_DTR(
|
||||
int minor
|
||||
);
|
||||
|
||||
NS16550_STATIC int ns16550_negate_DTR(
|
||||
int minor
|
||||
);
|
||||
|
||||
NS16550_STATIC void ns16550_initialize_interrupts(int minor);
|
||||
|
||||
NS16550_STATIC void ns16550_cleanup_interrupts(int minor);
|
||||
|
||||
NS16550_STATIC ssize_t ns16550_write_support_int(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
);
|
||||
|
||||
NS16550_STATIC ssize_t ns16550_write_support_polled(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
);
|
||||
|
||||
int ns16550_inbyte_nonblocking_polled(
|
||||
int minor
|
||||
);
|
||||
|
||||
NS16550_STATIC void ns16550_enable_interrupts(
|
||||
console_tbl *c,
|
||||
int mask
|
||||
);
|
||||
|
||||
NS16550_STATIC int ns16550_set_attributes(
|
||||
int minor,
|
||||
const struct termios *t
|
||||
);
|
||||
|
||||
#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
NS16550_STATIC void ns16550_isr(void *arg);
|
||||
#endif
|
||||
|
||||
RTEMS_INTERRUPT_LOCK_DEFINE(static, ns16550_lock, "NS16550")
|
||||
|
||||
/*
|
||||
* Flow control is only supported when using interrupts
|
||||
*/
|
||||
|
||||
const console_flow ns16550_flow_RTSCTS = {
|
||||
ns16550_negate_RTS, /* deviceStopRemoteTx */
|
||||
ns16550_assert_RTS /* deviceStartRemoteTx */
|
||||
};
|
||||
|
||||
const console_flow ns16550_flow_DTRCTS = {
|
||||
ns16550_negate_DTR, /* deviceStopRemoteTx */
|
||||
ns16550_assert_DTR /* deviceStartRemoteTx */
|
||||
};
|
||||
|
||||
const console_fns ns16550_fns = {
|
||||
libchip_serial_default_probe, /* deviceProbe */
|
||||
ns16550_open, /* deviceFirstOpen */
|
||||
ns16550_close, /* deviceLastClose */
|
||||
NULL, /* deviceRead */
|
||||
ns16550_write_support_int, /* deviceWrite */
|
||||
ns16550_init, /* deviceInitialize */
|
||||
ns16550_write_polled, /* deviceWritePolled */
|
||||
ns16550_set_attributes, /* deviceSetAttributes */
|
||||
true /* deviceOutputUsesInterrupts */
|
||||
};
|
||||
|
||||
const console_fns ns16550_fns_polled = {
|
||||
libchip_serial_default_probe, /* deviceProbe */
|
||||
ns16550_open, /* deviceFirstOpen */
|
||||
ns16550_close, /* deviceLastClose */
|
||||
ns16550_inbyte_nonblocking_polled, /* deviceRead */
|
||||
ns16550_write_support_polled, /* deviceWrite */
|
||||
ns16550_init, /* deviceInitialize */
|
||||
ns16550_write_polled, /* deviceWritePolled */
|
||||
ns16550_set_attributes, /* deviceSetAttributes */
|
||||
false /* deviceOutputUsesInterrupts */
|
||||
};
|
||||
|
||||
static uint32_t NS16550_GetBaudDivisor(const console_tbl *c, uint32_t baud)
|
||||
{
|
||||
uint32_t clock = c->ulClock;
|
||||
uint32_t baudDivisor = (clock != 0 ? clock : 115200) / (baud * 16);
|
||||
|
||||
if (c->deviceType == SERIAL_NS16550_WITH_FDR) {
|
||||
uint32_t fractionalDivider = 0x10;
|
||||
uint32_t err = baud;
|
||||
uint32_t mulVal;
|
||||
uint32_t divAddVal;
|
||||
|
||||
clock /= 16 * baudDivisor;
|
||||
for (mulVal = 1; mulVal < 16; ++mulVal) {
|
||||
for (divAddVal = 0; divAddVal < mulVal; ++divAddVal) {
|
||||
uint32_t actual = (mulVal * clock) / (mulVal + divAddVal);
|
||||
uint32_t newErr = actual > baud ? actual - baud : baud - actual;
|
||||
|
||||
if (newErr < err) {
|
||||
err = newErr;
|
||||
fractionalDivider = (mulVal << 4) | divAddVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*c->setRegister)(
|
||||
c->ulCtrlPort1,
|
||||
NS16550_FRACTIONAL_DIVIDER,
|
||||
fractionalDivider
|
||||
);
|
||||
}
|
||||
|
||||
return baudDivisor;
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_init
|
||||
*/
|
||||
|
||||
void ns16550_init(int minor)
|
||||
{
|
||||
uintptr_t pNS16550;
|
||||
uint8_t ucDataByte;
|
||||
uint32_t ulBaudDivisor;
|
||||
NS16550Context *pns16550Context;
|
||||
setRegister_f setReg;
|
||||
getRegister_f getReg;
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
|
||||
pns16550Context=(NS16550Context *)malloc(sizeof(NS16550Context));
|
||||
|
||||
if (pns16550Context == NULL) {
|
||||
printk( "%s: Error: Not enough memory\n", __func__);
|
||||
rtems_fatal_error_occurred( 0xdeadbeef);
|
||||
}
|
||||
|
||||
Console_Port_Data[minor].pDeviceContext=(void *)pns16550Context;
|
||||
pns16550Context->ucModemCtrl=SP_MODEM_IRQ;
|
||||
|
||||
pNS16550 = c->ulCtrlPort1;
|
||||
setReg = c->setRegister;
|
||||
getReg = c->getRegister;
|
||||
|
||||
/* Clear the divisor latch, clear all interrupt enables,
|
||||
* and reset and
|
||||
* disable the FIFO's.
|
||||
*/
|
||||
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, 0x0);
|
||||
ns16550_enable_interrupts( c, NS16550_DISABLE_ALL_INTR );
|
||||
|
||||
/* Set the divisor latch and set the baud rate. */
|
||||
|
||||
ulBaudDivisor = NS16550_GetBaudDivisor(c, (uintptr_t) c->pDeviceParams);
|
||||
ucDataByte = SP_LINE_DLAB;
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
|
||||
|
||||
/* XXX */
|
||||
(*setReg)(pNS16550,NS16550_TRANSMIT_BUFFER,(uint8_t)(ulBaudDivisor & 0xffU));
|
||||
(*setReg)(
|
||||
pNS16550,NS16550_INTERRUPT_ENABLE,
|
||||
(uint8_t)(( ulBaudDivisor >> 8 ) & 0xffU )
|
||||
);
|
||||
|
||||
/* Clear the divisor latch and set the character size to eight bits */
|
||||
/* with one stop bit and no parity checking. */
|
||||
ucDataByte = EIGHT_BITS;
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
|
||||
|
||||
/* Enable and reset transmit and receive FIFOs. TJA */
|
||||
ucDataByte = SP_FIFO_ENABLE;
|
||||
(*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
|
||||
|
||||
ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
|
||||
(*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
|
||||
|
||||
ns16550_enable_interrupts(c, NS16550_DISABLE_ALL_INTR);
|
||||
|
||||
/* Set data terminal ready. */
|
||||
/* And open interrupt tristate line */
|
||||
(*setReg)(pNS16550, NS16550_MODEM_CONTROL,pns16550Context->ucModemCtrl);
|
||||
|
||||
(*getReg)(pNS16550, NS16550_LINE_STATUS );
|
||||
(*getReg)(pNS16550, NS16550_RECEIVE_BUFFER );
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_open
|
||||
*/
|
||||
|
||||
int ns16550_open(
|
||||
int major,
|
||||
int minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_libio_open_close_args_t *oc = (rtems_libio_open_close_args_t *) arg;
|
||||
struct rtems_termios_tty *tty = (struct rtems_termios_tty *) oc->iop->data1;
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
console_data *d = &Console_Port_Data [minor];
|
||||
|
||||
d->termios_data = tty;
|
||||
|
||||
/* Assert DTR */
|
||||
if (c->pDeviceFlow != &ns16550_flow_DTRCTS) {
|
||||
ns16550_assert_DTR( minor);
|
||||
}
|
||||
|
||||
/* Set initial baud */
|
||||
rtems_termios_set_initial_baud( tty, (intptr_t) c->pDeviceParams);
|
||||
|
||||
if (c->pDeviceFns->deviceOutputUsesInterrupts) {
|
||||
ns16550_initialize_interrupts( minor);
|
||||
ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_close
|
||||
*/
|
||||
|
||||
int ns16550_close(
|
||||
int major,
|
||||
int minor,
|
||||
void * arg
|
||||
)
|
||||
{
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
|
||||
/*
|
||||
* Negate DTR
|
||||
*/
|
||||
if (c->pDeviceFlow != &ns16550_flow_DTRCTS) {
|
||||
ns16550_negate_DTR(minor);
|
||||
}
|
||||
|
||||
ns16550_enable_interrupts(c, NS16550_DISABLE_ALL_INTR);
|
||||
|
||||
if (c->pDeviceFns->deviceOutputUsesInterrupts) {
|
||||
ns16550_cleanup_interrupts(minor);
|
||||
}
|
||||
|
||||
return(RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Polled write for NS16550.
|
||||
*/
|
||||
void ns16550_outch_polled(console_tbl *c, char out)
|
||||
{
|
||||
uintptr_t port = c->ulCtrlPort1;
|
||||
getRegister_f get = c->getRegister;
|
||||
setRegister_f set = c->setRegister;
|
||||
uint32_t status = 0;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
|
||||
/* Save port interrupt mask */
|
||||
uint32_t interrupt_mask = get( port, NS16550_INTERRUPT_ENABLE);
|
||||
|
||||
/* Disable port interrupts */
|
||||
ns16550_enable_interrupts( c, NS16550_DISABLE_ALL_INTR);
|
||||
|
||||
while (true) {
|
||||
/* Try to transmit the character in a critical section */
|
||||
rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
|
||||
|
||||
/* Read the transmitter holding register and check it */
|
||||
status = get( port, NS16550_LINE_STATUS);
|
||||
if ((status & SP_LSR_THOLD) != 0) {
|
||||
/* Transmit character */
|
||||
set( port, NS16550_TRANSMIT_BUFFER, out);
|
||||
|
||||
/* Finished */
|
||||
rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
|
||||
break;
|
||||
} else {
|
||||
rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
|
||||
}
|
||||
|
||||
/* Wait for transmitter holding register to be empty */
|
||||
do {
|
||||
status = get( port, NS16550_LINE_STATUS);
|
||||
} while ((status & SP_LSR_THOLD) == 0);
|
||||
}
|
||||
|
||||
/* Restore port interrupt mask */
|
||||
set( port, NS16550_INTERRUPT_ENABLE, interrupt_mask);
|
||||
}
|
||||
|
||||
void ns16550_write_polled(int minor, char out)
|
||||
{
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
|
||||
ns16550_outch_polled( c, out );
|
||||
}
|
||||
|
||||
/*
|
||||
* These routines provide control of the RTS and DTR lines
|
||||
*/
|
||||
|
||||
/*
|
||||
* ns16550_assert_RTS
|
||||
*/
|
||||
|
||||
NS16550_STATIC int ns16550_assert_RTS(int minor)
|
||||
{
|
||||
uint32_t pNS16550;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
NS16550Context *pns16550Context;
|
||||
setRegister_f setReg;
|
||||
|
||||
pns16550Context=(NS16550Context *) Console_Port_Data[minor].pDeviceContext;
|
||||
|
||||
pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Assert RTS
|
||||
*/
|
||||
rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
|
||||
pns16550Context->ucModemCtrl|=SP_MODEM_RTS;
|
||||
(*setReg)(pNS16550, NS16550_MODEM_CONTROL, pns16550Context->ucModemCtrl);
|
||||
rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_negate_RTS
|
||||
*/
|
||||
|
||||
NS16550_STATIC int ns16550_negate_RTS(int minor)
|
||||
{
|
||||
uint32_t pNS16550;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
NS16550Context *pns16550Context;
|
||||
setRegister_f setReg;
|
||||
|
||||
pns16550Context=(NS16550Context *) Console_Port_Data[minor].pDeviceContext;
|
||||
|
||||
pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Negate RTS
|
||||
*/
|
||||
rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
|
||||
pns16550Context->ucModemCtrl&=~SP_MODEM_RTS;
|
||||
(*setReg)(pNS16550, NS16550_MODEM_CONTROL, pns16550Context->ucModemCtrl);
|
||||
rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* These flow control routines utilise a connection from the local DTR
|
||||
* line to the remote CTS line
|
||||
*/
|
||||
|
||||
/*
|
||||
* ns16550_assert_DTR
|
||||
*/
|
||||
|
||||
NS16550_STATIC int ns16550_assert_DTR(int minor)
|
||||
{
|
||||
uint32_t pNS16550;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
NS16550Context *pns16550Context;
|
||||
setRegister_f setReg;
|
||||
|
||||
pns16550Context=(NS16550Context *) Console_Port_Data[minor].pDeviceContext;
|
||||
|
||||
pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Assert DTR
|
||||
*/
|
||||
rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
|
||||
pns16550Context->ucModemCtrl|=SP_MODEM_DTR;
|
||||
(*setReg)(pNS16550, NS16550_MODEM_CONTROL, pns16550Context->ucModemCtrl);
|
||||
rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_negate_DTR
|
||||
*/
|
||||
|
||||
NS16550_STATIC int ns16550_negate_DTR(int minor)
|
||||
{
|
||||
uint32_t pNS16550;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
NS16550Context *pns16550Context;
|
||||
setRegister_f setReg;
|
||||
|
||||
pns16550Context=(NS16550Context *) Console_Port_Data[minor].pDeviceContext;
|
||||
|
||||
pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Negate DTR
|
||||
*/
|
||||
rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
|
||||
pns16550Context->ucModemCtrl&=~SP_MODEM_DTR;
|
||||
(*setReg)(pNS16550, NS16550_MODEM_CONTROL,pns16550Context->ucModemCtrl);
|
||||
rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_set_attributes
|
||||
*
|
||||
* This function sets the channel to reflect the requested termios
|
||||
* port settings.
|
||||
*/
|
||||
|
||||
int ns16550_set_attributes(
|
||||
int minor,
|
||||
const struct termios *t
|
||||
)
|
||||
{
|
||||
uint32_t pNS16550;
|
||||
uint32_t ulBaudDivisor;
|
||||
uint8_t ucLineControl;
|
||||
uint32_t baud_requested;
|
||||
setRegister_f setReg;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
const console_tbl *c = Console_Port_Tbl [minor];
|
||||
|
||||
pNS16550 = c->ulCtrlPort1;
|
||||
setReg = c->setRegister;
|
||||
|
||||
/*
|
||||
* Calculate the baud rate divisor
|
||||
*
|
||||
* Assert ensures there is no division by 0.
|
||||
*/
|
||||
|
||||
baud_requested = rtems_termios_baud_to_number(t->c_ospeed);
|
||||
_Assert( baud_requested != 0 );
|
||||
ulBaudDivisor = NS16550_GetBaudDivisor(c, baud_requested);
|
||||
|
||||
ucLineControl = 0;
|
||||
|
||||
/*
|
||||
* Parity
|
||||
*/
|
||||
|
||||
if (t->c_cflag & PARENB) {
|
||||
ucLineControl |= SP_LINE_PAR;
|
||||
if (!(t->c_cflag & PARODD))
|
||||
ucLineControl |= SP_LINE_ODD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Character Size
|
||||
*/
|
||||
|
||||
if (t->c_cflag & CSIZE) {
|
||||
switch (t->c_cflag & CSIZE) {
|
||||
case CS5: ucLineControl |= FIVE_BITS; break;
|
||||
case CS6: ucLineControl |= SIX_BITS; break;
|
||||
case CS7: ucLineControl |= SEVEN_BITS; break;
|
||||
case CS8: ucLineControl |= EIGHT_BITS; break;
|
||||
}
|
||||
} else {
|
||||
ucLineControl |= EIGHT_BITS; /* default to 9600,8,N,1 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop Bits
|
||||
*/
|
||||
|
||||
if (t->c_cflag & CSTOPB) {
|
||||
ucLineControl |= SP_LINE_STOP; /* 2 stop bits */
|
||||
} else {
|
||||
; /* 1 stop bit */
|
||||
}
|
||||
|
||||
/*
|
||||
* Now actually set the chip
|
||||
*/
|
||||
|
||||
rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
|
||||
|
||||
/*
|
||||
* Set the baud rate
|
||||
*
|
||||
* NOTE: When the Divisor Latch Access Bit (DLAB) is set to 1,
|
||||
* the transmit buffer and interrupt enable registers
|
||||
* turn into the LSB and MSB divisor latch registers.
|
||||
*/
|
||||
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, SP_LINE_DLAB);
|
||||
(*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, ulBaudDivisor&0xff);
|
||||
(*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff);
|
||||
|
||||
/*
|
||||
* Now write the line control
|
||||
*/
|
||||
(*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
|
||||
|
||||
rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
|
||||
/**
|
||||
* @brief Process interrupt.
|
||||
*/
|
||||
NS16550_STATIC void ns16550_process( int minor)
|
||||
{
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
console_data *d = &Console_Port_Data [minor];
|
||||
NS16550Context *ctx = d->pDeviceContext;
|
||||
uint32_t port = c->ulCtrlPort1;
|
||||
getRegister_f get = c->getRegister;
|
||||
int i;
|
||||
char buf [SP_FIFO_SIZE];
|
||||
|
||||
/* Iterate until no more interrupts are pending */
|
||||
do {
|
||||
/* Fetch received characters */
|
||||
i = 0;
|
||||
while ((get(port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
|
||||
buf[i++] = (char) get(port, NS16550_RECEIVE_BUFFER);
|
||||
if (i == SP_FIFO_SIZE) {
|
||||
/* Enqueue fetched characters */
|
||||
rtems_termios_enqueue_raw_characters( d->termios_data, buf, i);
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
rtems_termios_enqueue_raw_characters( d->termios_data, buf, i);
|
||||
|
||||
/* Check if we can dequeue transmitted characters */
|
||||
if (ctx->transmitFifoChars > 0
|
||||
&& (get( port, NS16550_LINE_STATUS) & SP_LSR_THOLD) != 0) {
|
||||
/* Dequeue transmitted characters */
|
||||
rtems_termios_dequeue_characters(
|
||||
d->termios_data,
|
||||
ctx->transmitFifoChars
|
||||
);
|
||||
}
|
||||
} while ((get( port, NS16550_INTERRUPT_ID) & SP_IID_0) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Transmits up to @a len characters from @a buf.
|
||||
*
|
||||
* This routine is invoked either from task context with disabled interrupts to
|
||||
* start a new transmission process with exactly one character in case of an
|
||||
* idle output state or from the interrupt handler to refill the transmitter.
|
||||
*
|
||||
* Returns always zero.
|
||||
*/
|
||||
ssize_t ns16550_write_support_int(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
console_data *d = &Console_Port_Data [minor];
|
||||
NS16550Context *ctx = d->pDeviceContext;
|
||||
uint32_t port = c->ulCtrlPort1;
|
||||
setRegister_f set = c->setRegister;
|
||||
int i = 0;
|
||||
int out = len > SP_FIFO_SIZE ? SP_FIFO_SIZE : len;
|
||||
|
||||
for (i = 0; i < out; ++i) {
|
||||
set( port, NS16550_TRANSMIT_BUFFER, buf [i]);
|
||||
}
|
||||
|
||||
ctx->transmitFifoChars = out;
|
||||
|
||||
if (out > 0) {
|
||||
ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR);
|
||||
} else {
|
||||
ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_enable_interrupts
|
||||
*
|
||||
* This routine initializes the port to have the specified interrupts masked.
|
||||
*/
|
||||
NS16550_STATIC void ns16550_enable_interrupts(
|
||||
console_tbl *c,
|
||||
int mask
|
||||
)
|
||||
{
|
||||
uint32_t pNS16550;
|
||||
setRegister_f setReg;
|
||||
|
||||
pNS16550 = c->ulCtrlPort1;
|
||||
setReg = c->setRegister;
|
||||
|
||||
(*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, mask);
|
||||
}
|
||||
|
||||
#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
void ns16550_isr(void *arg)
|
||||
{
|
||||
int minor = (intptr_t) arg;
|
||||
|
||||
ns16550_process( minor);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ns16550_initialize_interrupts
|
||||
*
|
||||
* This routine initializes the port to operate in interrupt driver mode.
|
||||
*/
|
||||
NS16550_STATIC void ns16550_initialize_interrupts( int minor)
|
||||
{
|
||||
#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
#endif
|
||||
|
||||
#ifdef BSP_FEATURE_IRQ_EXTENSION
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
sc = rtems_interrupt_handler_install(
|
||||
c->ulIntVector,
|
||||
"NS16550",
|
||||
RTEMS_INTERRUPT_SHARED,
|
||||
ns16550_isr,
|
||||
(void *) (intptr_t) minor
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
/* FIXME */
|
||||
printk( "%s: Error: Install interrupt handler\n", __func__);
|
||||
rtems_fatal_error_occurred( 0xdeadbeef);
|
||||
}
|
||||
}
|
||||
#elif defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
{
|
||||
int rv = 0;
|
||||
#ifdef BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
|
||||
rtems_irq_connect_data cd = {
|
||||
c->ulIntVector,
|
||||
ns16550_isr,
|
||||
(void *) minor,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
rv = BSP_install_rtems_shared_irq_handler( &cd);
|
||||
#else
|
||||
rtems_irq_connect_data cd = {
|
||||
c->ulIntVector,
|
||||
ns16550_isr,
|
||||
(void *) minor,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
rv = BSP_install_rtems_irq_handler( &cd);
|
||||
#endif
|
||||
if (rv == 0) {
|
||||
/* FIXME */
|
||||
printk( "%s: Error: Install interrupt handler\n", __func__);
|
||||
rtems_fatal_error_occurred( 0xdeadbeef);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NS16550_STATIC void ns16550_cleanup_interrupts(int minor)
|
||||
{
|
||||
#if defined(BSP_FEATURE_IRQ_EXTENSION)
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
sc = rtems_interrupt_handler_remove(
|
||||
c->ulIntVector,
|
||||
ns16550_isr,
|
||||
(void *) (intptr_t) minor
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
/* FIXME */
|
||||
printk("%s: Error: Remove interrupt handler\n", __func__);
|
||||
rtems_fatal_error_occurred(0xdeadbeef);
|
||||
}
|
||||
#elif defined(BSP_FEATURE_IRQ_LEGACY)
|
||||
int rv = 0;
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
rtems_irq_connect_data cd = {
|
||||
.name = c->ulIntVector,
|
||||
.hdl = ns16550_isr,
|
||||
.handle = (void *) minor
|
||||
};
|
||||
rv = BSP_remove_rtems_irq_handler(&cd);
|
||||
if (rv == 0) {
|
||||
/* FIXME */
|
||||
printk("%s: Error: Remove interrupt handler\n", __func__);
|
||||
rtems_fatal_error_occurred(0xdeadbeef);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_write_support_polled
|
||||
*
|
||||
* Console Termios output entry point.
|
||||
*
|
||||
*/
|
||||
|
||||
ssize_t ns16550_write_support_polled(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
int nwrite = 0;
|
||||
|
||||
/*
|
||||
* poll each byte in the string out of the port.
|
||||
*/
|
||||
while (nwrite < len) {
|
||||
/*
|
||||
* transmit character
|
||||
*/
|
||||
ns16550_write_polled(minor, *buf++);
|
||||
nwrite++;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the number of bytes written.
|
||||
*/
|
||||
return nwrite;
|
||||
}
|
||||
|
||||
/*
|
||||
* Debug gets() support
|
||||
*/
|
||||
int ns16550_inch_polled(
|
||||
console_tbl *c
|
||||
)
|
||||
{
|
||||
uint32_t pNS16550;
|
||||
unsigned char ucLineStatus;
|
||||
uint8_t cChar;
|
||||
getRegister_f getReg;
|
||||
|
||||
pNS16550 = c->ulCtrlPort1;
|
||||
getReg = c->getRegister;
|
||||
|
||||
ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
|
||||
if (ucLineStatus & SP_LSR_RDY) {
|
||||
cChar = (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER);
|
||||
return (int)cChar;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ns16550_inbyte_nonblocking_polled
|
||||
*
|
||||
* Console Termios polling input entry point.
|
||||
*/
|
||||
int ns16550_inbyte_nonblocking_polled(int minor)
|
||||
{
|
||||
console_tbl *c = Console_Port_Tbl [minor];
|
||||
|
||||
return ns16550_inch_polled( c );
|
||||
}
|
||||
13
bsps/shared/dev/serial/serprobe.c
Normal file
13
bsps/shared/dev/serial/serprobe.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <rtems.h>
|
||||
#include <libchip/serial.h>
|
||||
#include <libchip/sersupp.h>
|
||||
|
||||
bool libchip_serial_default_probe(int minor)
|
||||
{
|
||||
/*
|
||||
* If the configuration dependent probe has located the device then
|
||||
* assume it is there
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
893
bsps/shared/dev/serial/z85c30.c
Normal file
893
bsps/shared/dev/serial/z85c30.c
Normal file
@@ -0,0 +1,893 @@
|
||||
/*
|
||||
* This file contains the console driver chip level routines for the
|
||||
* Zilog z85c30 chip.
|
||||
*
|
||||
* The Zilog Z8530 is also available as:
|
||||
*
|
||||
* + Intel 82530
|
||||
* + AMD ???
|
||||
*
|
||||
* COPYRIGHT (c) 1998 by Radstone Technology
|
||||
*
|
||||
*
|
||||
* THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
|
||||
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
|
||||
* AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
|
||||
*
|
||||
* You are hereby granted permission to use, copy, modify, and distribute
|
||||
* this file, provided that this notice, plus the above copyright notice
|
||||
* and disclaimer, appears in all copies. Radstone Technology will provide
|
||||
* no support for this code.
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/score/sysstate.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <libchip/serial.h>
|
||||
#include <libchip/sersupp.h>
|
||||
#include "z85c30_p.h"
|
||||
|
||||
/*
|
||||
* Flow control is only supported when using interrupts
|
||||
*/
|
||||
|
||||
const console_flow z85c30_flow_RTSCTS = {
|
||||
z85c30_negate_RTS, /* deviceStopRemoteTx */
|
||||
z85c30_assert_RTS /* deviceStartRemoteTx */
|
||||
};
|
||||
|
||||
const console_flow z85c30_flow_DTRCTS = {
|
||||
z85c30_negate_DTR, /* deviceStopRemoteTx */
|
||||
z85c30_assert_DTR /* deviceStartRemoteTx */
|
||||
};
|
||||
|
||||
/*
|
||||
* Exported driver function table
|
||||
*/
|
||||
|
||||
const console_fns z85c30_fns = {
|
||||
libchip_serial_default_probe, /* deviceProbe */
|
||||
z85c30_open, /* deviceFirstOpen */
|
||||
NULL, /* deviceLastClose */
|
||||
NULL, /* deviceRead */
|
||||
z85c30_write_support_int, /* deviceWrite */
|
||||
z85c30_initialize_interrupts, /* deviceInitialize */
|
||||
z85c30_write_polled, /* deviceWritePolled */
|
||||
NULL, /* deviceSetAttributes */
|
||||
true /* deviceOutputUsesInterrupts */
|
||||
};
|
||||
|
||||
const console_fns z85c30_fns_polled = {
|
||||
libchip_serial_default_probe, /* deviceProbe */
|
||||
z85c30_open, /* deviceFirstOpen */
|
||||
z85c30_close, /* deviceLastClose */
|
||||
z85c30_inbyte_nonblocking_polled, /* deviceRead */
|
||||
z85c30_write_support_polled, /* deviceWrite */
|
||||
z85c30_init, /* deviceInitialize */
|
||||
z85c30_write_polled, /* deviceWritePolled */
|
||||
NULL, /* deviceSetAttributes */
|
||||
false /* deviceOutputUsesInterrupts */
|
||||
};
|
||||
|
||||
#if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
|
||||
extern void set_vector( rtems_isr_entry, rtems_vector_number, int );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* z85c30_initialize_port
|
||||
*
|
||||
* initialize a z85c30 Port
|
||||
*/
|
||||
|
||||
Z85C30_STATIC void z85c30_initialize_port(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
uintptr_t ulCtrlPort;
|
||||
uintptr_t ulBaudDivisor;
|
||||
setRegister_f setReg;
|
||||
|
||||
ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Using register 4
|
||||
* Set up the clock rate is 16 times the data
|
||||
* rate, 8 bit sync char, 1 stop bit, no parity
|
||||
*/
|
||||
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR4, SCC_WR4_1_STOP | SCC_WR4_16_CLOCK );
|
||||
|
||||
/*
|
||||
* Set up for 8 bits/character on receive with
|
||||
* receiver disable via register 3
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR3, SCC_WR3_RX_8_BITS );
|
||||
|
||||
/*
|
||||
* Set up for 8 bits/character on transmit
|
||||
* with transmitter disable via register 5
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR5, SCC_WR5_TX_8_BITS );
|
||||
|
||||
/*
|
||||
* Clear misc control bits
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR10, 0x00 );
|
||||
|
||||
/*
|
||||
* Setup the source of the receive and xmit
|
||||
* clock as BRG output and the transmit clock
|
||||
* as the output source for TRxC pin via register 11
|
||||
*/
|
||||
(*setReg)(
|
||||
ulCtrlPort,
|
||||
SCC_WR0_SEL_WR11,
|
||||
SCC_WR11_OUT_BR_GEN | SCC_WR11_TRXC_OI |
|
||||
SCC_WR11_TX_BR_GEN | SCC_WR11_RX_BR_GEN
|
||||
);
|
||||
|
||||
ulBaudDivisor = Z85C30_Baud(
|
||||
(uint32_t) Console_Port_Tbl[minor]->ulClock,
|
||||
(uint32_t) ((uintptr_t)Console_Port_Tbl[minor]->pDeviceParams)
|
||||
);
|
||||
|
||||
/*
|
||||
* Setup the lower 8 bits time constants=1E.
|
||||
* If the time constans=1E, then the desire
|
||||
* baud rate will be equilvalent to 9600, via register 12.
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR12, ulBaudDivisor & 0xff );
|
||||
|
||||
/*
|
||||
* using register 13
|
||||
* Setup the upper 8 bits time constant
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR13, (ulBaudDivisor>>8) & 0xff );
|
||||
|
||||
/*
|
||||
* Enable the baud rate generator enable with clock from the
|
||||
* SCC's PCLK input via register 14.
|
||||
*/
|
||||
(*setReg)(
|
||||
ulCtrlPort,
|
||||
SCC_WR0_SEL_WR14,
|
||||
SCC_WR14_BR_EN | SCC_WR14_BR_SRC | SCC_WR14_NULL
|
||||
);
|
||||
|
||||
/*
|
||||
* We are only interested in CTS state changes
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR15, SCC_WR15_CTS_IE );
|
||||
|
||||
/*
|
||||
* Reset errors
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT );
|
||||
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_ERR_RST );
|
||||
|
||||
/*
|
||||
* Enable the receiver via register 3
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR3, SCC_WR3_RX_8_BITS | SCC_WR3_RX_EN );
|
||||
|
||||
/*
|
||||
* Enable the transmitter pins set via register 5.
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR5, SCC_WR5_TX_8_BITS | SCC_WR5_TX_EN );
|
||||
|
||||
/*
|
||||
* Disable interrupts
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR1, 0 );
|
||||
|
||||
/*
|
||||
* Reset TX CRC
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_CRC );
|
||||
|
||||
/*
|
||||
* Reset interrupts
|
||||
*/
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT );
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_open
|
||||
*/
|
||||
|
||||
Z85C30_STATIC int z85c30_open(
|
||||
int major,
|
||||
int minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
|
||||
z85c30_initialize_port(minor);
|
||||
|
||||
/*
|
||||
* Assert DTR
|
||||
*/
|
||||
|
||||
if (Console_Port_Tbl[minor]->pDeviceFlow !=&z85c30_flow_DTRCTS) {
|
||||
z85c30_assert_DTR(minor);
|
||||
}
|
||||
|
||||
return(RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_close
|
||||
*/
|
||||
|
||||
Z85C30_STATIC int z85c30_close(
|
||||
int major,
|
||||
int minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
/*
|
||||
* Negate DTR
|
||||
*/
|
||||
|
||||
if (Console_Port_Tbl[minor]->pDeviceFlow !=&z85c30_flow_DTRCTS) {
|
||||
z85c30_negate_DTR(minor);
|
||||
}
|
||||
|
||||
return(RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_init
|
||||
*/
|
||||
|
||||
Z85C30_STATIC void z85c30_init(int minor)
|
||||
{
|
||||
uintptr_t ulCtrlPort;
|
||||
z85c30_context *pz85c30Context;
|
||||
setRegister_f setReg;
|
||||
getRegister_f getReg;
|
||||
|
||||
ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
getReg = Console_Port_Tbl[minor]->getRegister;
|
||||
|
||||
pz85c30Context = (z85c30_context *)malloc(sizeof(z85c30_context));
|
||||
|
||||
Console_Port_Data[minor].pDeviceContext = (void *)pz85c30Context;
|
||||
|
||||
pz85c30Context->ucModemCtrl = SCC_WR5_TX_8_BITS | SCC_WR5_TX_EN;
|
||||
|
||||
if ( ulCtrlPort == Console_Port_Tbl[minor]->ulCtrlPort2 ) {
|
||||
/*
|
||||
* This is channel A
|
||||
*/
|
||||
/*
|
||||
* Ensure port state machine is reset
|
||||
*/
|
||||
(*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
|
||||
|
||||
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR9, SCC_WR9_CH_A_RST);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* This is channel B
|
||||
*/
|
||||
/*
|
||||
* Ensure port state machine is reset
|
||||
*/
|
||||
(*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
|
||||
|
||||
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR9, SCC_WR9_CH_B_RST);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* These routines provide control of the RTS and DTR lines
|
||||
*/
|
||||
|
||||
/*
|
||||
* z85c30_assert_RTS
|
||||
*/
|
||||
|
||||
Z85C30_STATIC int z85c30_assert_RTS(int minor)
|
||||
{
|
||||
rtems_interrupt_level Irql;
|
||||
z85c30_context *pz85c30Context;
|
||||
setRegister_f setReg;
|
||||
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
pz85c30Context = (z85c30_context *) Console_Port_Data[minor].pDeviceContext;
|
||||
|
||||
/*
|
||||
* Assert RTS
|
||||
*/
|
||||
|
||||
rtems_interrupt_disable(Irql);
|
||||
pz85c30Context->ucModemCtrl|=SCC_WR5_RTS;
|
||||
(*setReg)(
|
||||
Console_Port_Tbl[minor]->ulCtrlPort1,
|
||||
SCC_WR0_SEL_WR5,
|
||||
pz85c30Context->ucModemCtrl
|
||||
);
|
||||
rtems_interrupt_enable(Irql);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_negate_RTS
|
||||
*/
|
||||
|
||||
Z85C30_STATIC int z85c30_negate_RTS(int minor)
|
||||
{
|
||||
rtems_interrupt_level Irql;
|
||||
z85c30_context *pz85c30Context;
|
||||
setRegister_f setReg;
|
||||
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
pz85c30Context = (z85c30_context *) Console_Port_Data[minor].pDeviceContext;
|
||||
|
||||
/*
|
||||
* Negate RTS
|
||||
*/
|
||||
|
||||
rtems_interrupt_disable(Irql);
|
||||
pz85c30Context->ucModemCtrl&=~SCC_WR5_RTS;
|
||||
(*setReg)(
|
||||
Console_Port_Tbl[minor]->ulCtrlPort1,
|
||||
SCC_WR0_SEL_WR5,
|
||||
pz85c30Context->ucModemCtrl
|
||||
);
|
||||
rtems_interrupt_enable(Irql);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* These flow control routines utilise a connection from the local DTR
|
||||
* line to the remote CTS line
|
||||
*/
|
||||
|
||||
/*
|
||||
* z85c30_assert_DTR
|
||||
*/
|
||||
|
||||
Z85C30_STATIC int z85c30_assert_DTR(int minor)
|
||||
{
|
||||
rtems_interrupt_level Irql;
|
||||
z85c30_context *pz85c30Context;
|
||||
setRegister_f setReg;
|
||||
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
pz85c30Context = (z85c30_context *) Console_Port_Data[minor].pDeviceContext;
|
||||
|
||||
/*
|
||||
* Assert DTR
|
||||
*/
|
||||
|
||||
rtems_interrupt_disable(Irql);
|
||||
pz85c30Context->ucModemCtrl|=SCC_WR5_DTR;
|
||||
(*setReg)(
|
||||
Console_Port_Tbl[minor]->ulCtrlPort1,
|
||||
SCC_WR0_SEL_WR5,
|
||||
pz85c30Context->ucModemCtrl
|
||||
);
|
||||
rtems_interrupt_enable(Irql);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_negate_DTR
|
||||
*/
|
||||
|
||||
Z85C30_STATIC int z85c30_negate_DTR(int minor)
|
||||
{
|
||||
rtems_interrupt_level Irql;
|
||||
z85c30_context *pz85c30Context;
|
||||
setRegister_f setReg;
|
||||
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
pz85c30Context = (z85c30_context *) Console_Port_Data[minor].pDeviceContext;
|
||||
|
||||
/*
|
||||
* Negate DTR
|
||||
*/
|
||||
|
||||
rtems_interrupt_disable(Irql);
|
||||
pz85c30Context->ucModemCtrl&=~SCC_WR5_DTR;
|
||||
(*setReg)(
|
||||
Console_Port_Tbl[minor]->ulCtrlPort1,
|
||||
SCC_WR0_SEL_WR5,
|
||||
pz85c30Context->ucModemCtrl
|
||||
);
|
||||
rtems_interrupt_enable(Irql);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_set_attributes
|
||||
*
|
||||
* This function sets the SCC channel to reflect the requested termios
|
||||
* port settings.
|
||||
*/
|
||||
|
||||
Z85C30_STATIC int z85c30_set_attributes(
|
||||
int minor,
|
||||
const struct termios *t
|
||||
)
|
||||
{
|
||||
uintptr_t ulCtrlPort;
|
||||
uint32_t ulBaudDivisor;
|
||||
uint32_t wr3;
|
||||
uint32_t wr4;
|
||||
uint32_t wr5;
|
||||
int baud_requested;
|
||||
uint32_t baud_number;
|
||||
setRegister_f setReg;
|
||||
rtems_interrupt_level Irql;
|
||||
|
||||
ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Calculate the baud rate divisor
|
||||
*
|
||||
* Assert ensures there is no division by 0.
|
||||
*/
|
||||
|
||||
baud_requested = t->c_ospeed;
|
||||
if (!baud_requested)
|
||||
baud_requested = B9600; /* default to 9600 baud */
|
||||
|
||||
baud_number = (uint32_t) rtems_termios_baud_to_number( baud_requested );
|
||||
_Assert( baud_number != 0 );
|
||||
|
||||
ulBaudDivisor = Z85C30_Baud(
|
||||
(uint32_t) Console_Port_Tbl[minor]->ulClock,
|
||||
baud_number
|
||||
);
|
||||
|
||||
wr3 = SCC_WR3_RX_EN;
|
||||
wr4 = SCC_WR4_16_CLOCK;
|
||||
wr5 = SCC_WR5_TX_EN;
|
||||
|
||||
/*
|
||||
* Parity
|
||||
*/
|
||||
|
||||
if (t->c_cflag & PARENB) {
|
||||
wr4 |= SCC_WR4_PAR_EN;
|
||||
if (!(t->c_cflag & PARODD))
|
||||
wr4 |= SCC_WR4_PAR_EVEN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Character Size
|
||||
*/
|
||||
|
||||
if (t->c_cflag & CSIZE) {
|
||||
switch (t->c_cflag & CSIZE) {
|
||||
case CS5: break;
|
||||
case CS6: wr3 |= SCC_WR3_RX_6_BITS; wr5 |= SCC_WR5_TX_6_BITS; break;
|
||||
case CS7: wr3 |= SCC_WR3_RX_7_BITS; wr5 |= SCC_WR5_TX_7_BITS; break;
|
||||
case CS8: wr3 |= SCC_WR3_RX_8_BITS; wr5 |= SCC_WR5_TX_8_BITS; break;
|
||||
}
|
||||
} else {
|
||||
wr3 |= SCC_WR3_RX_8_BITS; /* default to 9600,8,N,1 */
|
||||
wr5 |= SCC_WR5_TX_8_BITS; /* default to 9600,8,N,1 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop Bits
|
||||
*/
|
||||
|
||||
if (t->c_cflag & CSTOPB) {
|
||||
wr4 |= SCC_WR4_2_STOP; /* 2 stop bits */
|
||||
} else {
|
||||
wr4 |= SCC_WR4_1_STOP; /* 1 stop bits */
|
||||
}
|
||||
|
||||
/*
|
||||
* Now actually set the chip
|
||||
*/
|
||||
|
||||
rtems_interrupt_disable(Irql);
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR4, wr4 );
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR3, wr3 );
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR5, wr5 );
|
||||
|
||||
/*
|
||||
* Setup the lower 8 bits time constants=1E.
|
||||
* If the time constans=1E, then the desire
|
||||
* baud rate will be equilvalent to 9600, via register 12.
|
||||
*/
|
||||
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR12, ulBaudDivisor & 0xff );
|
||||
|
||||
/*
|
||||
* using register 13
|
||||
* Setup the upper 8 bits time constant
|
||||
*/
|
||||
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR13, (ulBaudDivisor>>8) & 0xff );
|
||||
|
||||
rtems_interrupt_enable(Irql);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_process
|
||||
*
|
||||
* This is the per port ISR handler.
|
||||
*/
|
||||
|
||||
Z85C30_STATIC void z85c30_process(
|
||||
int minor,
|
||||
uint8_t ucIntPend
|
||||
)
|
||||
{
|
||||
uint32_t ulCtrlPort;
|
||||
volatile uint8_t z85c30_status;
|
||||
char cChar;
|
||||
setRegister_f setReg;
|
||||
getRegister_f getReg;
|
||||
|
||||
ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
getReg = Console_Port_Tbl[minor]->getRegister;
|
||||
|
||||
/*
|
||||
* Deal with any received characters
|
||||
*/
|
||||
|
||||
while (ucIntPend&SCC_RR3_B_RX_IP)
|
||||
{
|
||||
z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
|
||||
if (!Z85C30_Status_Is_RX_character_available(z85c30_status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the character read.
|
||||
*/
|
||||
|
||||
cChar = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD8);
|
||||
|
||||
rtems_termios_enqueue_raw_characters(
|
||||
Console_Port_Data[minor].termios_data,
|
||||
&cChar,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* There could be a race condition here if there is not yet a TX
|
||||
* interrupt pending but the buffer is empty. This condition has
|
||||
* been seen before on other z8530 drivers but has not been seen
|
||||
* with this one. The typical solution is to use "vector includes
|
||||
* status" or to only look at the interrupts actually pending
|
||||
* in RR3.
|
||||
*/
|
||||
|
||||
while (true) {
|
||||
z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
|
||||
if (!Z85C30_Status_Is_TX_buffer_empty(z85c30_status)) {
|
||||
/*
|
||||
* We'll get another interrupt when
|
||||
* the transmitter holding reg. becomes
|
||||
* free again and we are clear to send
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!Z85C30_Status_Is_CTS_asserted(z85c30_status)) {
|
||||
/*
|
||||
* We can't transmit yet
|
||||
*/
|
||||
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_INT);
|
||||
/*
|
||||
* The next state change of CTS will wake us up
|
||||
*/
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
rtems_termios_dequeue_characters(Console_Port_Data[minor].termios_data, 1);
|
||||
if (rtems_termios_dequeue_characters(
|
||||
Console_Port_Data[minor].termios_data, 1)) {
|
||||
if (Console_Port_Tbl[minor]->pDeviceFlow != &z85c30_flow_RTSCTS) {
|
||||
z85c30_negate_RTS(minor);
|
||||
}
|
||||
Console_Port_Data[minor].bActive = FALSE;
|
||||
z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR_EXCEPT_TX);
|
||||
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_INT);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ucIntPend & SCC_RR3_B_EXT_IP) {
|
||||
/*
|
||||
* Clear the external status interrupt
|
||||
*/
|
||||
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT);
|
||||
z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset interrupts
|
||||
*/
|
||||
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_HI_IUS);
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_isr
|
||||
*
|
||||
* This is the ISR handler for each Z8530.
|
||||
*/
|
||||
|
||||
Z85C30_STATIC rtems_isr z85c30_isr(
|
||||
rtems_vector_number vector
|
||||
)
|
||||
{
|
||||
int minor;
|
||||
uint32_t ulCtrlPort;
|
||||
volatile uint8_t ucIntPend;
|
||||
volatile uint8_t ucIntPendPort;
|
||||
getRegister_f getReg;
|
||||
|
||||
for (minor=0;minor<Console_Port_Count;minor++) {
|
||||
if(Console_Port_Tbl[minor]->ulIntVector == vector &&
|
||||
Console_Port_Tbl[minor]->deviceType == SERIAL_Z85C30 ) {
|
||||
ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort2;
|
||||
getReg = Console_Port_Tbl[minor]->getRegister;
|
||||
do {
|
||||
ucIntPend = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD3);
|
||||
|
||||
/*
|
||||
* If this is channel A select channel A status
|
||||
*/
|
||||
|
||||
if (ulCtrlPort == Console_Port_Tbl[minor]->ulCtrlPort1) {
|
||||
ucIntPendPort = ucIntPend >> 3;
|
||||
ucIntPendPort &= 7;
|
||||
} else {
|
||||
ucIntPendPort = ucIntPend &= 7;
|
||||
}
|
||||
|
||||
if (ucIntPendPort) {
|
||||
z85c30_process(minor, ucIntPendPort);
|
||||
}
|
||||
} while (ucIntPendPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_enable_interrupts
|
||||
*
|
||||
* This routine enables the specified interrupts for this minor.
|
||||
*/
|
||||
|
||||
Z85C30_STATIC void z85c30_enable_interrupts(
|
||||
int minor,
|
||||
int interrupt_mask
|
||||
)
|
||||
{
|
||||
uint32_t ulCtrlPort;
|
||||
setRegister_f setReg;
|
||||
|
||||
ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR1, interrupt_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_initialize_interrupts
|
||||
*
|
||||
* This routine initializes the port to use interrupts.
|
||||
*/
|
||||
|
||||
Z85C30_STATIC void z85c30_initialize_interrupts(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
uint32_t ulCtrlPort1;
|
||||
setRegister_f setReg;
|
||||
|
||||
ulCtrlPort1 = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
|
||||
z85c30_init(minor);
|
||||
|
||||
Console_Port_Data[minor].bActive=FALSE;
|
||||
|
||||
z85c30_initialize_port( minor );
|
||||
|
||||
if (Console_Port_Tbl[minor]->pDeviceFlow != &z85c30_flow_RTSCTS) {
|
||||
z85c30_negate_RTS(minor);
|
||||
}
|
||||
|
||||
#if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
|
||||
set_vector(z85c30_isr, Console_Port_Tbl[minor]->ulIntVector, 1);
|
||||
#endif
|
||||
|
||||
z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR_EXCEPT_TX);
|
||||
|
||||
(*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR2, 0); /* XXX vector */
|
||||
(*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR9, SCC_WR9_MIE);
|
||||
|
||||
/*
|
||||
* Reset interrupts
|
||||
*/
|
||||
|
||||
(*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT);
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_write_support_int
|
||||
*
|
||||
* Console Termios output entry point.
|
||||
*
|
||||
*/
|
||||
|
||||
Z85C30_STATIC ssize_t z85c30_write_support_int(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
uint32_t Irql;
|
||||
uint32_t ulCtrlPort;
|
||||
setRegister_f setReg;
|
||||
|
||||
ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* We are using interrupt driven output and termios only sends us
|
||||
* one character at a time.
|
||||
*/
|
||||
|
||||
if ( !len )
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Put the character out and enable interrupts if necessary.
|
||||
*/
|
||||
|
||||
if (Console_Port_Tbl[minor]->pDeviceFlow != &z85c30_flow_RTSCTS) {
|
||||
z85c30_assert_RTS(minor);
|
||||
}
|
||||
rtems_interrupt_disable(Irql);
|
||||
if ( Console_Port_Data[minor].bActive == FALSE) {
|
||||
Console_Port_Data[minor].bActive = TRUE;
|
||||
z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR);
|
||||
}
|
||||
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR8, *buf);
|
||||
rtems_interrupt_enable(Irql);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_inbyte_nonblocking_polled
|
||||
*
|
||||
* This routine polls for a character.
|
||||
*/
|
||||
|
||||
Z85C30_STATIC int z85c30_inbyte_nonblocking_polled(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
volatile uint8_t z85c30_status;
|
||||
uint32_t ulCtrlPort;
|
||||
getRegister_f getReg;
|
||||
|
||||
ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
getReg = Console_Port_Tbl[minor]->getRegister;
|
||||
|
||||
/*
|
||||
* return -1 if a character is not available.
|
||||
*/
|
||||
z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
|
||||
if (!Z85C30_Status_Is_RX_character_available(z85c30_status)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the character read.
|
||||
*/
|
||||
|
||||
return (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD8);
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_write_support_polled
|
||||
*
|
||||
* Console Termios output entry point.
|
||||
*
|
||||
*/
|
||||
|
||||
Z85C30_STATIC ssize_t z85c30_write_support_polled(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
int nwrite=0;
|
||||
|
||||
/*
|
||||
* poll each byte in the string out of the port.
|
||||
*/
|
||||
while (nwrite < len) {
|
||||
z85c30_write_polled(minor, *buf++);
|
||||
nwrite++;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the number of bytes written.
|
||||
*/
|
||||
return nwrite;
|
||||
}
|
||||
|
||||
/*
|
||||
* z85c30_write_polled
|
||||
*
|
||||
* This routine transmits a character using polling.
|
||||
*/
|
||||
|
||||
Z85C30_STATIC void z85c30_write_polled(
|
||||
int minor,
|
||||
char cChar
|
||||
)
|
||||
{
|
||||
volatile uint8_t z85c30_status;
|
||||
uint32_t ulCtrlPort;
|
||||
getRegister_f getReg;
|
||||
setRegister_f setReg;
|
||||
|
||||
ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
|
||||
getReg = Console_Port_Tbl[minor]->getRegister;
|
||||
setReg = Console_Port_Tbl[minor]->setRegister;
|
||||
|
||||
/*
|
||||
* Wait for the Transmit buffer to indicate that it is empty.
|
||||
*/
|
||||
|
||||
z85c30_status = (*getReg)( ulCtrlPort, SCC_WR0_SEL_RD0 );
|
||||
|
||||
while (!Z85C30_Status_Is_TX_buffer_empty(z85c30_status)) {
|
||||
/*
|
||||
* Yield while we wait
|
||||
*/
|
||||
#if 0
|
||||
if (_System_state_Is_up(_System_state_Get())) {
|
||||
rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
|
||||
}
|
||||
#endif
|
||||
z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the character.
|
||||
*/
|
||||
|
||||
(*setReg)( ulCtrlPort, SCC_WR0_SEL_WR8, cChar );
|
||||
}
|
||||
420
bsps/shared/dev/serial/z85c30_p.h
Normal file
420
bsps/shared/dev/serial/z85c30_p.h
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* This include file contains all private driver definitions for the
|
||||
* Zilog z85c30.
|
||||
*
|
||||
* COPYRIGHT (c) 1998 by Radstone Technology
|
||||
*
|
||||
*
|
||||
* THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
|
||||
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
|
||||
* AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
|
||||
*
|
||||
* You are hereby granted permission to use, copy, modify, and distribute
|
||||
* this file, provided that this notice, plus the above copyright notice
|
||||
* and disclaimer, appears in all copies. Radstone Technology will provide
|
||||
* no support for this code.
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may in
|
||||
* the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifndef __Z85C30_P_H
|
||||
#define __Z85C30_P_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define Z85C30_STATIC to nothing while debugging so the entry points
|
||||
* will show up in the symbol table.
|
||||
*/
|
||||
|
||||
#define Z85C30_STATIC
|
||||
|
||||
/* #define Z85C30_STATIC static */
|
||||
|
||||
/* bit values for write register 0 */
|
||||
/* command register */
|
||||
|
||||
#define SCC_WR0_SEL_WR0 0x00
|
||||
#define SCC_WR0_SEL_WR1 0x01
|
||||
#define SCC_WR0_SEL_WR2 0x02
|
||||
#define SCC_WR0_SEL_WR3 0x03
|
||||
#define SCC_WR0_SEL_WR4 0x04
|
||||
#define SCC_WR0_SEL_WR5 0x05
|
||||
#define SCC_WR0_SEL_WR6 0x06
|
||||
#define SCC_WR0_SEL_WR7 0x07
|
||||
#define SCC_WR0_SEL_WR8 0x08
|
||||
#define SCC_WR0_SEL_WR9 0x09
|
||||
#define SCC_WR0_SEL_WR10 0x0a
|
||||
#define SCC_WR0_SEL_WR11 0x0b
|
||||
#define SCC_WR0_SEL_WR12 0x0c
|
||||
#define SCC_WR0_SEL_WR13 0x0d
|
||||
#define SCC_WR0_SEL_WR14 0x0e
|
||||
#define SCC_WR0_SEL_WR15 0x0f
|
||||
#define SCC_WR0_SEL_RD0 0x00
|
||||
#define SCC_WR0_SEL_RD1 0x01
|
||||
#define SCC_WR0_SEL_RD2 0x02
|
||||
#define SCC_WR0_SEL_RD3 0x03
|
||||
#define SCC_WR0_SEL_RD4 0x04
|
||||
#define SCC_WR0_SEL_RD5 0x05
|
||||
#define SCC_WR0_SEL_RD6 0x06
|
||||
#define SCC_WR0_SEL_RD7 0x07
|
||||
#define SCC_WR0_SEL_RD8 0x08
|
||||
#define SCC_WR0_SEL_RD9 0x09
|
||||
#define SCC_WR0_SEL_RD10 0x0a
|
||||
#define SCC_WR0_SEL_RD11 0x0b
|
||||
#define SCC_WR0_SEL_RD12 0x0c
|
||||
#define SCC_WR0_SEL_RD13 0x0d
|
||||
#define SCC_WR0_SEL_RD14 0x0e
|
||||
#define SCC_WR0_SEL_RD15 0x0f
|
||||
#define SCC_WR0_NULL_CODE 0x00
|
||||
#define SCC_WR0_RST_INT 0x10
|
||||
#define SCC_WR0_SEND_ABORT 0x18
|
||||
#define SCC_WR0_EN_INT_RX 0x20
|
||||
#define SCC_WR0_RST_TX_INT 0x28
|
||||
#define SCC_WR0_ERR_RST 0x30
|
||||
#define SCC_WR0_RST_HI_IUS 0x38
|
||||
#define SCC_WR0_RST_RX_CRC 0x40
|
||||
#define SCC_WR0_RST_TX_CRC 0x80
|
||||
#define SCC_WR0_RST_TX_UND 0xc0
|
||||
|
||||
/* write register 2 */
|
||||
/* interrupt vector */
|
||||
|
||||
/* bit values for write register 1 */
|
||||
/* tx/rx interrupt and data transfer mode definition */
|
||||
|
||||
#define SCC_WR1_EXT_INT_EN 0x01
|
||||
#define SCC_WR1_TX_INT_EN 0x02
|
||||
#define SCC_WR1_PARITY 0x04
|
||||
#define SCC_WR1_RX_INT_DIS 0x00
|
||||
#define SCC_WR1_RX_INT_FIR 0x08
|
||||
#define SCC_WR1_INT_ALL_RX 0x10
|
||||
#define SCC_WR1_RX_INT_SPE 0x18
|
||||
#define SCC_WR1_RDMA_RECTR 0x20
|
||||
#define SCC_WR1_RDMA_FUNC 0x40
|
||||
#define SCC_WR1_RDMA_EN 0x80
|
||||
|
||||
#define SCC_ENABLE_ALL_INTR \
|
||||
(SCC_WR1_EXT_INT_EN | SCC_WR1_TX_INT_EN | SCC_WR1_INT_ALL_RX)
|
||||
|
||||
#define SCC_DISABLE_ALL_INTR 0x00
|
||||
|
||||
#define SCC_ENABLE_ALL_INTR_EXCEPT_TX \
|
||||
(SCC_WR1_EXT_INT_EN | SCC_WR1_INT_ALL_RX)
|
||||
|
||||
/* bit values for write register 3 */
|
||||
/* receive parameters and control */
|
||||
|
||||
#define SCC_WR3_RX_EN 0x01
|
||||
#define SCC_WR3_SYNC_CHAR 0x02
|
||||
#define SCC_WR3_ADR_SEARCH 0x04
|
||||
#define SCC_WR3_RX_CRC_EN 0x08
|
||||
#define SCC_WR3_ENTER_HUNT 0x10
|
||||
#define SCC_WR3_AUTO_EN 0x20
|
||||
#define SCC_WR3_RX_5_BITS 0x00
|
||||
#define SCC_WR3_RX_7_BITS 0x40
|
||||
#define SCC_WR3_RX_6_BITS 0x80
|
||||
#define SCC_WR3_RX_8_BITS 0xc0
|
||||
|
||||
/* bit values for write register 4 */
|
||||
/* tx/rx misc parameters and modes */
|
||||
|
||||
#define SCC_WR4_PAR_EN 0x01
|
||||
#define SCC_WR4_PAR_EVEN 0x02
|
||||
#define SCC_WR4_SYNC_EN 0x00
|
||||
#define SCC_WR4_1_STOP 0x04
|
||||
#define SCC_WR4_2_STOP 0x0c
|
||||
#define SCC_WR4_8_SYNC 0x00
|
||||
#define SCC_WR4_16_SYNC 0x10
|
||||
#define SCC_WR4_SDLC 0x20
|
||||
#define SCC_WR4_EXT_SYNC 0x30
|
||||
#define SCC_WR4_1_CLOCK 0x00
|
||||
#define SCC_WR4_16_CLOCK 0x40
|
||||
#define SCC_WR4_32_CLOCK 0x80
|
||||
#define SCC_WR4_64_CLOCK 0xc0
|
||||
|
||||
/* bit values for write register 5 */
|
||||
/* transmit parameter and controls */
|
||||
|
||||
#define SCC_WR5_TX_CRC_EN 0x01
|
||||
#define SCC_WR5_RTS 0x02
|
||||
#define SCC_WR5_SDLC 0x04
|
||||
#define SCC_WR5_TX_EN 0x08
|
||||
#define SCC_WR5_SEND_BRK 0x10
|
||||
|
||||
#define SCC_WR5_TX_5_BITS 0x00
|
||||
#define SCC_WR5_TX_7_BITS 0x20
|
||||
#define SCC_WR5_TX_6_BITS 0x40
|
||||
#define SCC_WR5_TX_8_BITS 0x60
|
||||
#define SCC_WR5_DTR 0x80
|
||||
|
||||
/* write register 6 */
|
||||
/* sync chars or sdlc address field */
|
||||
|
||||
/* write register 7 */
|
||||
/* sync char or sdlc flag */
|
||||
|
||||
/* write register 8 */
|
||||
/* transmit buffer */
|
||||
|
||||
/* bit values for write register 9 */
|
||||
/* master interrupt control */
|
||||
|
||||
#define SCC_WR9_VIS 0x01
|
||||
#define SCC_WR9_NV 0x02
|
||||
#define SCC_WR9_DLC 0x04
|
||||
#define SCC_WR9_MIE 0x08
|
||||
#define SCC_WR9_STATUS_HI 0x10
|
||||
#define SCC_WR9_NO_RST 0x00
|
||||
#define SCC_WR9_CH_B_RST 0x40
|
||||
#define SCC_WR9_CH_A_RST 0x80
|
||||
#define SCC_WR9_HDWR_RST 0xc0
|
||||
|
||||
/* bit values for write register 10 */
|
||||
/* misc tx/rx control bits */
|
||||
|
||||
#define SCC_WR10_6_BIT_SYNC 0x01
|
||||
#define SCC_WR10_LOOP_MODE 0x02
|
||||
#define SCC_WR10_ABORT_UND 0x04
|
||||
#define SCC_WR10_MARK_IDLE 0x08
|
||||
#define SCC_WR10_ACT_POLL 0x10
|
||||
#define SCC_WR10_NRZ 0x00
|
||||
#define SCC_WR10_NRZI 0x20
|
||||
#define SCC_WR10_FM1 0x40
|
||||
#define SCC_WR10_FM0 0x60
|
||||
#define SCC_WR10_CRC_PRESET 0x80
|
||||
|
||||
/* bit values for write register 11 */
|
||||
/* clock mode control */
|
||||
|
||||
#define SCC_WR11_OUT_XTAL 0x00
|
||||
#define SCC_WR11_OUT_TX_CLK 0x01
|
||||
#define SCC_WR11_OUT_BR_GEN 0x02
|
||||
#define SCC_WR11_OUT_DPLL 0x03
|
||||
#define SCC_WR11_TRXC_OI 0x04
|
||||
#define SCC_WR11_TX_RTXC 0x00
|
||||
#define SCC_WR11_TX_TRXC 0x08
|
||||
#define SCC_WR11_TX_BR_GEN 0x10
|
||||
#define SCC_WR11_TX_DPLL 0x18
|
||||
#define SCC_WR11_RX_RTXC 0x00
|
||||
#define SCC_WR11_RX_TRXC 0x20
|
||||
#define SCC_WR11_RX_BR_GEN 0x40
|
||||
#define SCC_WR11_RX_DPLL 0x60
|
||||
#define SCC_WR11_RTXC_XTAL 0x80
|
||||
|
||||
/* write register 12 */
|
||||
/* lower byte of baud rate generator time constant */
|
||||
|
||||
/* write register 13 */
|
||||
/* upper byte of baud rate generator time constant */
|
||||
|
||||
/* bit values for write register 14 */
|
||||
/* misc control bits */
|
||||
|
||||
#define SCC_WR14_BR_EN 0x01
|
||||
#define SCC_WR14_BR_SRC 0x02
|
||||
#define SCC_WR14_DTR_FUNC 0x04
|
||||
#define SCC_WR14_AUTO_ECHO 0x08
|
||||
#define SCC_WR14_LCL_LOOP 0x10
|
||||
#define SCC_WR14_NULL 0x00
|
||||
#define SCC_WR14_SEARCH 0x20
|
||||
#define SCC_WR14_RST_CLK 0x40
|
||||
#define SCC_WR14_DIS_DPLL 0x60
|
||||
#define SCC_WR14_SRC_BR 0x80
|
||||
#define SCC_WR14_SRC_RTXC 0xa0
|
||||
#define SCC_WR14_FM_MODE 0xc0
|
||||
#define SCC_WR14_NRZI 0xe0
|
||||
|
||||
/* bit values for write register 15 */
|
||||
/* external/status interrupt control */
|
||||
|
||||
#define SCC_WR15_ZERO_CNT 0x02
|
||||
#define SCC_WR15_CD_IE 0x08
|
||||
#define SCC_WR15_SYNC_IE 0x10
|
||||
#define SCC_WR15_CTS_IE 0x20
|
||||
#define SCC_WR15_TX_UND_IE 0x40
|
||||
#define SCC_WR15_BREAK_IE 0x80
|
||||
|
||||
/* bit values for read register 0 */
|
||||
/* tx/rx buffer status and external status */
|
||||
|
||||
#define SCC_RR0_RX_AVAIL 0x01
|
||||
#define SCC_RR0_ZERO_CNT 0x02
|
||||
#define SCC_RR0_TX_EMPTY 0x04
|
||||
#define SCC_RR0_CD 0x08
|
||||
#define SCC_RR0_SYNC 0x10
|
||||
#define SCC_RR0_CTS 0x20
|
||||
#define SCC_RR0_TX_UND 0x40
|
||||
#define SCC_RR0_BREAK 0x80
|
||||
|
||||
/* bit values for read register 1 */
|
||||
|
||||
#define SCC_RR1_ALL_SENT 0x01
|
||||
#define SCC_RR1_RES_CD_2 0x02
|
||||
#define SCC_RR1_RES_CD_1 0x01
|
||||
#define SCC_RR1_RES_CD_0 0x08
|
||||
#define SCC_RR1_PAR_ERR 0x10
|
||||
#define SCC_RR1_RX_OV_ERR 0x20
|
||||
#define SCC_RR1_CRC_ERR 0x40
|
||||
#define SCC_RR1_END_FRAME 0x80
|
||||
|
||||
/* read register 2 */
|
||||
/* interrupt vector */
|
||||
|
||||
/* bit values for read register 3 */
|
||||
/* interrupt pending register */
|
||||
|
||||
#define SCC_RR3_B_EXT_IP 0x01
|
||||
#define SCC_RR3_B_TX_IP 0x02
|
||||
#define SCC_RR3_B_RX_IP 0x04
|
||||
#define SCC_RR3_A_EXT_IP 0x08
|
||||
#define SCC_RR3_A_TX_IP 0x10
|
||||
#define SCC_RR3_A_RX_IP 0x20
|
||||
|
||||
/* read register 8 */
|
||||
/* receive data register */
|
||||
|
||||
/* bit values for read register 10 */
|
||||
/* misc status bits */
|
||||
|
||||
#define SCC_RR10_ON_LOOP 0x02
|
||||
#define SCC_RR10_LOOP_SEND 0x10
|
||||
#define SCC_RR10_2_CLK_MIS 0x40
|
||||
#define SCC_RR10_1_CLK_MIS 0x80
|
||||
|
||||
/* read register 12 */
|
||||
/* lower byte of time constant */
|
||||
|
||||
/* read register 13 */
|
||||
/* upper byte of time constant */
|
||||
|
||||
/* bit values for read register 15 */
|
||||
/* external/status ie bits */
|
||||
|
||||
#define SCC_RR15_ZERO_CNT 0x02
|
||||
#define SCC_RR15_CD_IE 0x08
|
||||
#define SCC_RR15_SYNC_IE 0x10
|
||||
#define SCC_RR15_CTS_IE 0x20
|
||||
#define SCC_RR15_TX_UND_IE 0x40
|
||||
#define SCC_RR15_BREAK_IE 0x80
|
||||
|
||||
typedef struct _z85c30_context
|
||||
{
|
||||
uint8_t ucModemCtrl;
|
||||
} z85c30_context;
|
||||
|
||||
/*
|
||||
* The following macro calculates the Baud constant. For the Z85C30 chip.
|
||||
*
|
||||
* Note: baud constant = ((clock frequency / Clock_X) / (2 * Baud Rate)) - 2
|
||||
* eg ((10,000,000 / 16) / (2 * Baud Rate)) - 2
|
||||
*/
|
||||
|
||||
#define Z85C30_Baud( _clock, _baud_rate ) \
|
||||
( ((_clock) /( 16 * 2 * _baud_rate)) - 2)
|
||||
|
||||
#define Z85C30_Status_Is_RX_character_available(_status) \
|
||||
((_status) & SCC_RR0_RX_AVAIL)
|
||||
|
||||
#define Z85C30_Status_Is_TX_buffer_empty(_status) \
|
||||
((_status) & SCC_RR0_TX_EMPTY)
|
||||
|
||||
#define Z85C30_Status_Is_CTS_asserted(_status) \
|
||||
((_status) & SCC_RR0_CTS)
|
||||
|
||||
#define Z85C30_Status_Is_break_abort(_status) \
|
||||
((_status) & SCC_RR0_BREAK)
|
||||
|
||||
/*
|
||||
* Private routines
|
||||
*/
|
||||
|
||||
Z85C30_STATIC void z85c30_initialize_port(
|
||||
int minor
|
||||
);
|
||||
|
||||
Z85C30_STATIC void z85c30_init(int minor);
|
||||
|
||||
Z85C30_STATIC int z85c30_set_attributes(
|
||||
int minor,
|
||||
const struct termios *t
|
||||
);
|
||||
|
||||
Z85C30_STATIC int z85c30_open(
|
||||
int major,
|
||||
int minor,
|
||||
void * arg
|
||||
);
|
||||
|
||||
Z85C30_STATIC int z85c30_close(
|
||||
int major,
|
||||
int minor,
|
||||
void * arg
|
||||
);
|
||||
|
||||
Z85C30_STATIC void z85c30_write_polled(
|
||||
int minor,
|
||||
char cChar
|
||||
);
|
||||
|
||||
Z85C30_STATIC int z85c30_assert_RTS(
|
||||
int minor
|
||||
);
|
||||
|
||||
Z85C30_STATIC int z85c30_negate_RTS(
|
||||
int minor
|
||||
);
|
||||
|
||||
Z85C30_STATIC int z85c30_assert_DTR(
|
||||
int minor
|
||||
);
|
||||
|
||||
Z85C30_STATIC int z85c30_negate_DTR(
|
||||
int minor
|
||||
);
|
||||
|
||||
Z85C30_STATIC void z85c30_initialize_interrupts(int minor);
|
||||
|
||||
Z85C30_STATIC ssize_t z85c30_write_support_int(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
);
|
||||
|
||||
Z85C30_STATIC ssize_t z85c30_write_support_polled(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
);
|
||||
|
||||
Z85C30_STATIC int z85c30_inbyte_nonblocking_polled(
|
||||
int minor
|
||||
);
|
||||
|
||||
Z85C30_STATIC void z85c30_enable_interrupts(
|
||||
int minor,
|
||||
int interrupt_mask
|
||||
);
|
||||
|
||||
Z85C30_STATIC void z85c30_process(
|
||||
int minor,
|
||||
uint8_t ucIntPend
|
||||
);
|
||||
|
||||
Z85C30_STATIC rtems_isr z85c30_isr(
|
||||
rtems_vector_number vector
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
72
bsps/shared/dev/serial/z85c30_reg.c
Normal file
72
bsps/shared/dev/serial/z85c30_reg.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file contains a typical set of register access routines which may be
|
||||
* used with the z85c30 chip if accesses to the chip are as follows:
|
||||
*
|
||||
* + registers are accessed as bytes
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#include <libchip/z85c30.h>
|
||||
|
||||
#ifndef _Z85C30_MULTIPLIER
|
||||
#define _Z85C30_MULTIPLIER 1
|
||||
#define _Z85C30_NAME(_X) _X
|
||||
#define _Z85C30_TYPE uint8_t
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Z85C30 Get Register Routine
|
||||
*/
|
||||
|
||||
uint8_t _Z85C30_NAME(z85c30_get_register)(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum
|
||||
)
|
||||
{
|
||||
_Z85C30_TYPE *port;
|
||||
uint8_t data;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
port = (_Z85C30_TYPE *)ulCtrlPort;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
|
||||
if(ucRegNum) {
|
||||
*port = ucRegNum;
|
||||
}
|
||||
data = *port;
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Z85C30 Set Register Routine
|
||||
*/
|
||||
|
||||
void _Z85C30_NAME(z85c30_set_register)(
|
||||
uintptr_t ulCtrlPort,
|
||||
uint8_t ucRegNum,
|
||||
uint8_t ucData
|
||||
)
|
||||
{
|
||||
_Z85C30_TYPE *port;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
port = (_Z85C30_TYPE *)ulCtrlPort;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
if(ucRegNum) {
|
||||
*port = ucRegNum;
|
||||
}
|
||||
*port = ucData;
|
||||
rtems_interrupt_enable(level);
|
||||
}
|
||||
Reference in New Issue
Block a user