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:
@@ -23,7 +23,6 @@ RTEMS_ENV_RTEMSBSP
|
||||
RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP)
|
||||
|
||||
RTEMS_CHECK_POSIX_API(RTEMS_BSP)
|
||||
RTEMS_CHECK_SMP
|
||||
|
||||
AC_MSG_NOTICE([setting up make/custom])
|
||||
|
||||
@@ -111,7 +110,6 @@ RTEMS_CHECK_GCC_WEAK
|
||||
|
||||
AC_SUBST(CUSTOM_CFG_FILES)
|
||||
|
||||
RTEMS_CHECK_NETWORKING(RTEMS_BSP)
|
||||
RTEMS_CHECK_MULTIPROCESSING
|
||||
|
||||
BSP_SUBDIRS=
|
||||
@@ -155,9 +153,6 @@ AS_IF([test "$host_cpu" = sparc],[
|
||||
[whether to enable ipalignment work-around])
|
||||
])
|
||||
|
||||
AM_CONDITIONAL([HAS_NETWORKING],[test "$HAS_NETWORKING" = "yes"])
|
||||
AM_CONDITIONAL(HAS_SMP,[test "$rtems_cv_HAS_SMP" = "yes"])
|
||||
|
||||
RTEMS_PROJECT_ROOT
|
||||
|
||||
# Explicitly list all Makefiles here
|
||||
|
||||
@@ -57,7 +57,7 @@ libbsp_a_SOURCES += console/console.c
|
||||
libbsp_a_SOURCES += i2c/i2c.c i2c/i2cdrv.c i2c/mpc5200mbus.c i2c/mpc5200mbus.h
|
||||
# ide
|
||||
libbsp_a_SOURCES += ide/idecfg.c ide/pcmcia_ide.c ide/pcmcia_ide.h
|
||||
libbsp_a_SOURCES += ide/ata.c
|
||||
libbsp_a_SOURCES += ../../../../../../bsps/powerpc/gen5200/dev/mpc5200-ata.c
|
||||
libbsp_a_SOURCES += ide/ata-instance.c
|
||||
libbsp_a_SOURCES += ide/ata-dma-pio-single.c
|
||||
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include <bsp/ata.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/fatal.h>
|
||||
#include <bsp/mpc5200.h>
|
||||
|
||||
#include <libcpu/powerpc-utility.h>
|
||||
|
||||
bool ata_execute_io_command(uint8_t command, uint32_t lba, uint32_t sector_count_32)
|
||||
{
|
||||
assert(sector_count_32 >= 1);
|
||||
assert(sector_count_32 <= 256);
|
||||
|
||||
assert(ata_is_drive_ready_for_selection());
|
||||
|
||||
ATA->write.head = (uint8_t) (0xe0 | ((lba >> 24) & 0x0f));
|
||||
|
||||
ata_wait_400_nano_seconds();
|
||||
ata_wait_for_drive_ready();
|
||||
|
||||
/*
|
||||
* It seems that the write to the ATA device registers is sometimes not
|
||||
* successful. The write is retried until the read back values are all right
|
||||
* or a timeout is reached.
|
||||
*/
|
||||
bool ok = false;
|
||||
uint8_t sector = (uint8_t) lba;
|
||||
uint8_t cylinder_low = (uint8_t) (lba >> 8);
|
||||
uint8_t cylinder_high = (uint8_t) (lba >> 16);
|
||||
uint8_t sector_count = (uint8_t) sector_count_32;
|
||||
int i;
|
||||
for (i = 0; !ok && i < 100; ++i) {
|
||||
ATA->write.sector = sector;
|
||||
ATA->write.cylinder_low = cylinder_low;
|
||||
ATA->write.cylinder_high = cylinder_high;
|
||||
ATA->write.sector_count = sector_count;
|
||||
|
||||
uint8_t actual_sector = ATA->read.sector;
|
||||
uint8_t actual_cylinder_low = ATA->read.cylinder_low;
|
||||
uint8_t actual_cylinder_high = ATA->read.cylinder_high;
|
||||
uint8_t actual_sector_count = ATA->read.sector_count;
|
||||
|
||||
ok = actual_cylinder_high == cylinder_high
|
||||
&& actual_cylinder_low == cylinder_low
|
||||
&& actual_sector == sector
|
||||
&& actual_sector_count == sector_count;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
ATA->write.command = command;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ata_reset_device(void)
|
||||
{
|
||||
/* ATA/ATAPI-7 V2, 11.2 Software reset protocol */
|
||||
ATA->write.control = DCTRL_SRST;
|
||||
rtems_bsp_delay(5);
|
||||
ATA->write.control = 0;
|
||||
rtems_bsp_delay(2000);
|
||||
ata_wait_for_not_busy();
|
||||
}
|
||||
|
||||
bool ata_set_transfer_mode(uint8_t mode)
|
||||
{
|
||||
assert(ata_is_drive_ready_for_selection());
|
||||
|
||||
ATA->write.head = 0xe0;
|
||||
|
||||
ata_wait_400_nano_seconds();
|
||||
ata_wait_for_drive_ready();
|
||||
|
||||
ATA->write.feature = 0x3;
|
||||
ATA->write.sector_count = mode;
|
||||
ATA->write.command = 0xef;
|
||||
|
||||
ata_wait_for_not_busy();
|
||||
|
||||
return ata_check_status();
|
||||
}
|
||||
|
||||
static bool probe(void)
|
||||
{
|
||||
bool card_present = true;
|
||||
|
||||
#ifdef MPC5200_BOARD_BRS5L
|
||||
volatile struct mpc5200_gpt *gpt = &mpc5200.gpt[GPT2];
|
||||
|
||||
/* Enable card detection on GPT2 */
|
||||
gpt->emsel = (GPT_EMSEL_GPIO_IN | GPT_EMSEL_TIMER_MS_GPIO);
|
||||
|
||||
/* Check for card detection (-CD0) */
|
||||
if ((gpt->status & GPT_STATUS_PIN) != 0) {
|
||||
card_present = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return card_present;
|
||||
}
|
||||
|
||||
static void create_lock(ata_driver *self)
|
||||
{
|
||||
rtems_status_code sc = rtems_semaphore_create(
|
||||
rtems_build_name('A', 'T', 'A', ' '),
|
||||
1,
|
||||
RTEMS_LOCAL | RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
|
||||
0,
|
||||
&self->lock
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC5200_FATAL_ATA_LOCK_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
static void destroy_lock(const ata_driver *self)
|
||||
{
|
||||
rtems_status_code sc = rtems_semaphore_delete(self->lock);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC5200_FATAL_ATA_LOCK_DESTROY);
|
||||
}
|
||||
}
|
||||
|
||||
void ata_driver_create(ata_driver *self, const char *device_file_path, rtems_block_device_ioctl io_control)
|
||||
{
|
||||
self->card_present = probe();
|
||||
|
||||
if (ata_driver_is_card_present(self)) {
|
||||
create_lock(self);
|
||||
ata_reset_device();
|
||||
|
||||
uint16_t sector_buffer[256];
|
||||
ata_dev_t ata_device;
|
||||
rtems_status_code sc = ata_identify_device(0, 0, sector_buffer, &ata_device);
|
||||
|
||||
if (sc == RTEMS_SUCCESSFUL && ata_device.lba_avaible) {
|
||||
sc = ide_controller_config_io_speed(0, ata_device.modes_available);
|
||||
|
||||
if (sc == RTEMS_SUCCESSFUL) {
|
||||
sc = rtems_blkdev_create(
|
||||
device_file_path,
|
||||
ATA_SECTOR_SIZE,
|
||||
ata_device.lba_sectors,
|
||||
io_control,
|
||||
self
|
||||
);
|
||||
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC5200_FATAL_ATA_DISK_CREATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ata_driver_destroy(ata_driver *self)
|
||||
{
|
||||
destroy_lock(self);
|
||||
/* TODO */
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static bool transfer_pio_polled(ata_driver *self, bool read, rtems_blkdev_sg_buffer *sg, size_t sg_count)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
ata_sg_context sg_context;
|
||||
ata_sg_create(&sg_context, sg, sg_count);
|
||||
rtems_blkdev_bnum start_sector = ata_sg_get_start_sector(&sg_context);
|
||||
rtems_blkdev_bnum sector_count = ata_sg_get_sector_count(&sg_context);
|
||||
rtems_blkdev_bnum relative_sector = 0;
|
||||
|
||||
uint8_t command = ata_read_or_write_sectors_command(read);
|
||||
|
||||
while (ok && relative_sector < sector_count) {
|
||||
rtems_blkdev_bnum remaining_sectors = sector_count - relative_sector;
|
||||
rtems_blkdev_bnum transfer_count = ata_max_transfer_count(remaining_sectors);
|
||||
rtems_blkdev_bnum transfer_end = relative_sector + transfer_count;
|
||||
|
||||
ok = ata_execute_io_command(command, start_sector + relative_sector, transfer_count);
|
||||
|
||||
rtems_blkdev_bnum transfer;
|
||||
for (transfer = relative_sector; ok && transfer < transfer_end; ++transfer) {
|
||||
uint16_t *current = ata_sg_get_sector_data_begin(&sg_context, transfer);
|
||||
uint16_t *end = ata_sg_get_sector_data_end(&sg_context, current);
|
||||
|
||||
ok = ata_wait_for_data_request();
|
||||
|
||||
if (ok) {
|
||||
if (read) {
|
||||
while (current != end) {
|
||||
*current = ATA->read.data;
|
||||
++current;
|
||||
}
|
||||
} else {
|
||||
while (current != end) {
|
||||
ATA->write.data = *current;
|
||||
++current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
ata_wait_for_not_busy();
|
||||
ok = ata_check_status();
|
||||
}
|
||||
|
||||
relative_sector += ATA_PER_TRANSFER_SECTOR_COUNT_MAX;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int ata_driver_io_control_pio_polled(
|
||||
rtems_disk_device *dd,
|
||||
uint32_t cmd,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
return ata_driver_io_control(dd, cmd, arg, transfer_pio_polled);
|
||||
}
|
||||
@@ -1,77 +1,8 @@
|
||||
include $(top_srcdir)/automake/compile.am
|
||||
|
||||
noinst_LIBRARIES =
|
||||
noinst_PROGRAMS =
|
||||
|
||||
# display
|
||||
noinst_LIBRARIES += libdisplay.a
|
||||
libdisplay_a_SOURCES = display/disp_hcms29xx.c display/font_hcms29xx.c
|
||||
libdisplay_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
# flash
|
||||
noinst_LIBRARIES += libflash.a
|
||||
libflash_a_SOURCES = flash/am29lv160.c
|
||||
libflash_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
# ide
|
||||
noinst_LIBRARIES += libide.a
|
||||
libide_a_SOURCES = ide/ata.c ide/ata_util.c ide/ide_controller.c
|
||||
libide_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
# network
|
||||
if HAS_NETWORKING
|
||||
noinst_LIBRARIES += libnetchip.a
|
||||
libnetchip_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libnetchip_a_SOURCES = network/cs8900.c network/dec21140.c network/i82586.c \
|
||||
network/sonic.c network/if_fxp.c network/elnk.c network/open_eth.c \
|
||||
network/if_dc.c
|
||||
if !HAS_SMP
|
||||
libnetchip_a_SOURCES += network/greth.c
|
||||
endif
|
||||
libnetchip_a_SOURCES += network/smc91111.c network/smc91111config.h
|
||||
endif
|
||||
|
||||
|
||||
# rtc
|
||||
noinst_LIBRARIES += librtcio.a
|
||||
librtcio_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
librtcio_a_SOURCES = rtc/rtcprobe.c rtc/icm7170.c rtc/icm7170_reg.c \
|
||||
rtc/icm7170_reg2.c rtc/icm7170_reg4.c rtc/icm7170_reg8.c rtc/m48t08.c \
|
||||
rtc/m48t08_reg.c rtc/m48t08_reg2.c rtc/m48t08_reg4.c rtc/m48t08_reg8.c \
|
||||
rtc/mc146818a.c rtc/mc146818a_ioreg.c rtc/ds1375.c
|
||||
|
||||
|
||||
# i2c
|
||||
noinst_LIBRARIES += libi2cio.a
|
||||
|
||||
libi2cio_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libi2cio_a_SOURCES = i2c/i2c-ds1621.h \
|
||||
i2c/i2c-2b-eeprom.h \
|
||||
i2c/spi-memdrv.h \
|
||||
i2c/spi-flash-m25p40.h \
|
||||
i2c/spi-fram-fm25l256.h \
|
||||
i2c/i2c-ds1621.c \
|
||||
i2c/i2c-2b-eeprom.c \
|
||||
i2c/i2c-sc620.c \
|
||||
i2c/spi-memdrv.c \
|
||||
i2c/spi-flash-m25p40.c \
|
||||
i2c/spi-fram-fm25l256.c \
|
||||
i2c/spi-sd-card.c
|
||||
|
||||
# serial
|
||||
noinst_LIBRARIES += libserialio.a
|
||||
libserialio_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libserialio_a_SOURCES = serial/mc68681.c serial/mc68681_baud.c \
|
||||
serial/mc68681_reg.c serial/mc68681_reg2.c serial/mc68681_reg4.c \
|
||||
serial/mc68681_reg8.c serial/ns16550.c serial/z85c30.c \
|
||||
serial/z85c30_reg.c serial/serprobe.c serial/mc68681_p.h \
|
||||
serial/z85c30_p.h
|
||||
libserialio_a_SOURCES += serial/ns16550-context.c
|
||||
|
||||
|
||||
## shmdr
|
||||
if HAS_MP
|
||||
noinst_LIBRARIES += libshmdr.a
|
||||
noinst_LIBRARIES = libshmdr.a
|
||||
libshmdr_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libshmdr_a_SOURCES = shmdr/addlq.c shmdr/cnvpkt.c shmdr/getlq.c shmdr/dump.c \
|
||||
shmdr/fatal.c shmdr/getpkt.c shmdr/init.c shmdr/initlq.c shmdr/intr.c \
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/*===============================================================*\
|
||||
| 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 */
|
||||
@@ -1,932 +0,0 @@
|
||||
/*===============================================================*\
|
||||
| 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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
||||
/*===============================================================*\
|
||||
| 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 */
|
||||
@@ -1,473 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
@@ -1,177 +0,0 @@
|
||||
/* 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;
|
||||
@@ -1,128 +0,0 @@
|
||||
/* 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;
|
||||
@@ -1,95 +0,0 @@
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#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)
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
/*===============================================================*\
|
||||
| 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;
|
||||
@@ -1,60 +0,0 @@
|
||||
/*===============================================================*\
|
||||
| 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;
|
||||
@@ -1,442 +0,0 @@
|
||||
/*===============================================================*\
|
||||
| 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,
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,215 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
This is the network interface controller portion of the libchip library.
|
||||
This directory contains the source code for reusable TCP/IP network driver
|
||||
support code. Each driver has its own configuration table and its
|
||||
chip specific attach routine must be called by a board specific
|
||||
attach routine. The board specific chip routine passes the chip
|
||||
configuration and network configuration to the resuable device driver.
|
||||
|
||||
The reusable chip drivers do not directly access the controller.
|
||||
They access the registers on the controller via a set of
|
||||
functions which are provided by the BSP. These functions set and get
|
||||
general registers and data buffers.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#
|
||||
# README.3com
|
||||
#
|
||||
@@ -1,26 +0,0 @@
|
||||
Target Support
|
||||
==============
|
||||
|
||||
The target is required to provide the low level support routines as
|
||||
listed in the Configuration section of this file.
|
||||
|
||||
The file cs8900.[ch].bsp are an example BSP files for DIMMPC target.
|
||||
|
||||
Conditionals
|
||||
============
|
||||
CS8900_DATA_BUS_SWAPPED - XXX
|
||||
|
||||
CS8900_TRACE - XXX
|
||||
|
||||
CS8900_VERBOSE - XXX
|
||||
|
||||
Todo
|
||||
====
|
||||
+ Build two versions -- one with swapped, one without.
|
||||
|
||||
+ Document conditionals.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
See the cs8900.h header file for the documentation.
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
This TULIP driver can be used on BSPs that support PCI bus.
|
||||
|
||||
It can handle any DEC21140 and DEC21143 based Ethernet controller
|
||||
although the DEC21143 support has only been tested on Intel.
|
||||
|
||||
It works on big or little endian target.
|
||||
|
||||
The DEC21140 has been tested with powerpc/mcp750 BSP (OnBoard Ethernet
|
||||
controller) and i386/pc386 BSP (D-Link DFE-500TX Ethernet board).
|
||||
|
||||
The DEC21143 has been tested only on the i386/pc386 using
|
||||
the Kingston KNE100TX with 21143PD chip.
|
||||
|
||||
*****************************************************************
|
||||
******** ***************
|
||||
******** tests with ttcp benchmark for DEC driver ***************
|
||||
******** optimization ***************
|
||||
******** ***************
|
||||
*****************************************************************
|
||||
|
||||
|
||||
LINUX -> LINUX-ix86
|
||||
|
||||
Transmitter :
|
||||
|
||||
ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> genesis
|
||||
ttcp-t: 16777216 bytes in 1.87 real seconds = 8775.25 KB/sec +++
|
||||
ttcp-t: 2048 I/O calls, msec/call = 0.93, calls/sec = 1096.91
|
||||
ttcp-t: 0.0user 0.9sys 0:01real 51% 0i+0d 0maxrss 0+2pf 0+0csw
|
||||
|
||||
Receiver :
|
||||
|
||||
ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
|
||||
ttcp-r: 16777216 bytes in 1.88 real seconds = 8706.53 KB/sec +++
|
||||
ttcp-r: 10802 I/O calls, msec/call = 0.18, calls/sec = 5740.23
|
||||
ttcp-r: 0.0user 0.2sys 0:01real 13% 0i+0d 0maxrss 0+2pf 0+0csw
|
||||
|
||||
==============================================================
|
||||
==============================================================
|
||||
==============================================================
|
||||
|
||||
LINUX -> RTEMS-ix86 with tulip driver from pc386 bsp
|
||||
|
||||
Transmitter :
|
||||
|
||||
ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> neil-young-100
|
||||
ttcp-t: 16777216 bytes in 1.98 real seconds = 8294.76 KB/sec +++
|
||||
ttcp-t: 2048 I/O calls, msec/call = 0.99, calls/sec = 1036.85
|
||||
ttcp-t: 0.0user 0.1sys 0:01real 9% 0i+0d 0maxrss 0+2pf 0+0csw
|
||||
|
||||
Receiver :
|
||||
|
||||
ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
|
||||
ttcp-r: 16777216 bytes in 2.03 real seconds = 8065.14 KB/sec +++
|
||||
ttcp-r: 3088 I/O calls, msec/call = 0.67, calls/sec = 1520.09
|
||||
ttcp-r: 0.0user 2.0sys 0:02real 100% 0i+0d 0maxrss 0+0pf 0+0csw
|
||||
|
||||
==============================================================
|
||||
==============================================================
|
||||
==============================================================
|
||||
|
||||
RTEMS-ix86 with tulip driver from pc386 bsp -> LINUX
|
||||
|
||||
Transmitter :
|
||||
|
||||
ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> 194.2.81.126
|
||||
ttcp-t: 16777216 bytes in 2.76 real seconds = 5938.77 KB/sec +++
|
||||
ttcp-t: 2048 I/O calls, msec/call = 1.38, calls/sec = 742.35
|
||||
ttcp-t: 0.0user 2.5sys 0:02real 100% 0i+0d 0maxrss 0+0pf 0+0csw
|
||||
|
||||
Receiver :
|
||||
|
||||
ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
|
||||
ttcp-r: 16777216 bytes in 2.75 real seconds = 5948.53 KB/sec +++
|
||||
ttcp-r: 11349 I/O calls, msec/call = 0.25, calls/sec = 4120.48
|
||||
ttcp-r: 0.0user 0.1sys 0:02real 6% 0i+0d 0maxrss 0+2pf 0+0csw
|
||||
|
||||
==============================================================
|
||||
==============================================================
|
||||
==============================================================
|
||||
|
||||
LINUX -> RTEMS-ix86 with optimized tulip driver
|
||||
|
||||
Transmitter :
|
||||
|
||||
ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> neil-young-100
|
||||
ttcp-t: 16777216 bytes in 1.73 real seconds = 9470.13 KB/sec +++
|
||||
ttcp-t: 2048 I/O calls, msec/call = 0.87, calls/sec = 1183.77
|
||||
ttcp-t: 0.0user 0.1sys 0:01real 6% 0i+0d 0maxrss 0+2pf 0+0csw
|
||||
|
||||
Receiver :
|
||||
|
||||
ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
|
||||
ttcp-r: 16777216 bytes in 1.76 real seconds = 9315.33 KB/sec +++
|
||||
ttcp-r: 4558 I/O calls, msec/call = 0.40, calls/sec = 2591.51
|
||||
ttcp-r: 0.0user 1.7sys 0:01real 100% 0i+0d 0maxrss 0+0pf 0+0csw
|
||||
|
||||
==============================================================
|
||||
==============================================================
|
||||
==============================================================
|
||||
|
||||
RTEMS-ix86 with optimized tulip driver -> LINUX
|
||||
|
||||
Transmitter :
|
||||
|
||||
ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> 194.2.81.126
|
||||
ttcp-t: 16777216 bytes in 2.09 real seconds = 7847.80 KB/sec +++
|
||||
ttcp-t: 2048 I/O calls, msec/call = 1.04, calls/sec = 980.98
|
||||
ttcp-t: 0.0user 2.0sys 0:02real 100% 0i+0d 0maxrss 0+0pf 0+0csw
|
||||
|
||||
Receiver :
|
||||
|
||||
ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
|
||||
ttcp-r: 16777216 bytes in 2.08 real seconds = 7874.23 KB/sec +++
|
||||
ttcp-r: 11404 I/O calls, msec/call = 0.19, calls/sec = 5480.82
|
||||
ttcp-r: 0.0user 0.1sys 0:02real 8% 0i+0d 0maxrss 0+2pf 0+0csw
|
||||
@@ -1 +0,0 @@
|
||||
TBD
|
||||
@@ -1,72 +0,0 @@
|
||||
Driver for opencores ethernet MAC - README
|
||||
------------------------------------------
|
||||
|
||||
The device name for the driver is 'open_eth1', the attach
|
||||
function for the leon bsp is rtems_leon_open_eth_driver_attach().
|
||||
|
||||
No cache flushing is made when a frame is received. On leon,
|
||||
this means that cache snooping must be configured in the
|
||||
vhdl model and enabled by software.
|
||||
|
||||
TX interrupts are not used and masked in the interrupt mask
|
||||
register.
|
||||
|
||||
For now, only 10 Mbit/s half-duplex is supported.
|
||||
100 Mbit/s operations does not work reliably, the transmitter
|
||||
locks up or skips frames. Seems to depend on the TX fifo
|
||||
implementation in the opencores MAC. Send a mail to
|
||||
jiri@gaisler.com if you know how to fix this.
|
||||
|
||||
Tested only on leon, using the GR-PCI-XC2V board @ 40 MHz.
|
||||
Output from ttcp receiving 1 Mbyte file:
|
||||
|
||||
>>> ttcp -r -s
|
||||
ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
|
||||
ttcp-r: socket
|
||||
ttcp-r: accept from 192.168.0.2
|
||||
ttcp-r: 1145339 bytes in 1.18 real seconds = 947.88 KB/sec +++
|
||||
ttcp-r: 792 I/O calls, msec/call = 1.53, calls/sec = 671.19
|
||||
ttcp-r: 0.0user 1.1sys 0:01real 100% 0i+0d 0maxrss 0+0pf 0+0csw
|
||||
************ MBUF STATISTICS ************
|
||||
mbufs:1024 clusters: 128 free: 112
|
||||
drops: 0 waits: 0 drains: 0
|
||||
free:1007 data:17 header:0 socket:0
|
||||
pcb:0 rtable:0 htable:0 atable:0
|
||||
soname:0 soopts:0 ftable:0 rights:0
|
||||
ifaddr:0 control:0 oobdata:0
|
||||
|
||||
************ INTERFACE STATISTICS ************
|
||||
***** open_eth1 *****
|
||||
Address:192.168.0.66 Broadcast Address:192.168.0.255
|
||||
Flags: Up Broadcast Running Simplex
|
||||
Send queue limit:50 length:0 Dropped:0
|
||||
Rx Packets:796 Rx Interrupts:796 Length:0
|
||||
Bad CRC:0 Overrun:0 Miss:0
|
||||
Tx Interrupts:0 Deferred:0 Missed Hearbeat:0
|
||||
No Carrier:0 Retransmit Limit:0 Late Collision:0
|
||||
Underrun:0 Raw output wait:0
|
||||
|
||||
************ IP Statistics ************
|
||||
total packets received 795
|
||||
datagrams delivered to upper level 795
|
||||
total ip packets generated here 401
|
||||
|
||||
************ TCP Statistics ************
|
||||
connections accepted 1
|
||||
connections established 1
|
||||
conn. closed (includes drops) 1
|
||||
segs where we tried to get rtt 2
|
||||
times we succeeded 2
|
||||
delayed acks sent 4
|
||||
total packets sent 401
|
||||
ack-only packets sent 6
|
||||
window update-only packets sent 394
|
||||
control (SYN|FIN|RST) packets sent 1
|
||||
total packets received 795
|
||||
packets received in sequence 792
|
||||
bytes received in sequence 1145339
|
||||
rcvd ack packets 2
|
||||
bytes acked by rcvd acks 2
|
||||
times hdr predict ok for data pkts 791
|
||||
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
This SONIC driver does not make any attempt to support the SONIC chip
|
||||
in any of the following modes:
|
||||
|
||||
+ 16-bit
|
||||
+ little endian
|
||||
|
||||
It does not attempt to handle SONIC's older than Revision C. There is
|
||||
a bug in chips before that revision that must be handled in the driver.
|
||||
|
||||
The configuration table should be discussed here but if you look in the
|
||||
include file for the sonic, it is reasonably obvious. :)
|
||||
|
||||
The performance impact of transforming this driver into libchip format
|
||||
was minimal.
|
||||
|
||||
The powerpc/dmv177 BSP used this driver and the following should
|
||||
serve as an example configuration table. This BSP was obsoleted after
|
||||
the 4.6 release series so the code is included here.
|
||||
|
||||
======================================================================
|
||||
|
||||
/*
|
||||
* DMV177 SONIC Configuration Information
|
||||
*
|
||||
* References:
|
||||
*
|
||||
* 1) SVME/DMV-171 Single Board Computer Documentation Package, #805905,
|
||||
* DY 4 Systems Inc., Kanata, Ontario, September, 1996.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
#include <libchip/sonic.h>
|
||||
|
||||
void dmv177_sonic_write_register(
|
||||
void *base,
|
||||
unsigned32 regno,
|
||||
unsigned32 value
|
||||
)
|
||||
{
|
||||
volatile unsigned32 *p = base;
|
||||
|
||||
#if (SONIC_DEBUG & SONIC_DEBUG_PRINT_REGISTERS)
|
||||
printf( "%p Write 0x%04x to %s (0x%02x)\n",
|
||||
&p[regno], value, SONIC_Reg_name[regno], regno );
|
||||
fflush( stdout );
|
||||
#endif
|
||||
p[regno] = value;
|
||||
}
|
||||
|
||||
unsigned32 dmv177_sonic_read_register(
|
||||
void *base,
|
||||
unsigned32 regno
|
||||
)
|
||||
{
|
||||
volatile unsigned32 *p = base;
|
||||
unsigned32 value;
|
||||
|
||||
value = p[regno];
|
||||
#if (SONIC_DEBUG & SONIC_DEBUG_PRINT_REGISTERS)
|
||||
printf( "%p Read 0x%04x from %s (0x%02x)\n",
|
||||
&p[regno], value, SONIC_Reg_name[regno], regno );
|
||||
fflush( stdout );
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Default sizes of transmit and receive descriptor areas
|
||||
*/
|
||||
#define RDA_COUNT 20 /* 20 */
|
||||
#define TDA_COUNT 20 /* 10 */
|
||||
|
||||
/*
|
||||
* Default device configuration register values
|
||||
* Conservative, generic values.
|
||||
* DCR:
|
||||
* No extended bus mode
|
||||
* Unlatched bus retry
|
||||
* Programmable outputs unused
|
||||
* Asynchronous bus mode
|
||||
* User definable pins unused
|
||||
* No wait states (access time controlled by DTACK*)
|
||||
* 32-bit DMA
|
||||
* Empty/Fill DMA mode
|
||||
* Maximum Transmit/Receive FIFO
|
||||
* DC2:
|
||||
* Extended programmable outputs unused
|
||||
* Normal HOLD request
|
||||
* Packet compress output unused
|
||||
* No reject on CAM match
|
||||
*/
|
||||
#define SONIC_DCR \
|
||||
(DCR_DW32 | DCR_WAIT0 | DCR_PO0 | DCR_PO1 | DCR_RFT24 | DCR_TFT28)
|
||||
#ifndef SONIC_DCR
|
||||
# define SONIC_DCR (DCR_DW32 | DCR_TFT28)
|
||||
#endif
|
||||
#ifndef SONIC_DC2
|
||||
# define SONIC_DC2 (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default location of device registers
|
||||
*/
|
||||
#ifndef SONIC_BASE_ADDRESS
|
||||
# define SONIC_BASE_ADDRESS 0xF3000000
|
||||
# warning "Using default SONIC_BASE_ADDRESS."
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default interrupt vector
|
||||
*/
|
||||
#ifndef SONIC_VECTOR
|
||||
# define SONIC_VECTOR 1
|
||||
# warning "Using default SONIC_VECTOR."
|
||||
#endif
|
||||
|
||||
sonic_configuration_t dmv177_sonic_configuration = {
|
||||
SONIC_BASE_ADDRESS, /* base address */
|
||||
SONIC_VECTOR, /* vector number */
|
||||
SONIC_DCR, /* DCR register value */
|
||||
SONIC_DC2, /* DC2 register value */
|
||||
TDA_COUNT, /* number of transmit descriptors */
|
||||
RDA_COUNT, /* number of receive descriptors */
|
||||
dmv177_sonic_write_register,
|
||||
dmv177_sonic_read_register
|
||||
};
|
||||
|
||||
int rtems_dmv177_sonic_driver_attach(struct rtems_bsdnet_ifconfig *config)
|
||||
{
|
||||
return rtems_sonic_driver_attach( config, &dmv177_sonic_configuration );
|
||||
|
||||
}
|
||||
|
||||
======================================================================
|
||||
@@ -1,101 +0,0 @@
|
||||
*****************************************************************
|
||||
******** ***************
|
||||
******** ttcp benchmark tests of dec2114x driver ***************
|
||||
******** adapted from FreeBSD's if_dc.c for RTEMS ***************
|
||||
******** by: Daron Chabot (12/15/03), ***************
|
||||
******** <daron@nucleus.usask.ca> ***************
|
||||
*****************************************************************
|
||||
|
||||
Test Equipment:
|
||||
-----------------------
|
||||
- Intel 450 MHz P3's
|
||||
- RH Linux v7.3, 2.4.7-10 kernel, D-Link DFE-530TX (via-rhine)
|
||||
- RTEMS rtems-ss-20030703, pc386 BSP, Linksys LNE100TX ( actually,
|
||||
a cleverly disguised ADMtek Centaur, aka "Comet").
|
||||
- the PCs were directly connected ( RJ-45 X-over cable ) on a class C
|
||||
subnet (private)
|
||||
|
||||
NOTE:
|
||||
-----------------------
|
||||
- the following lines must be added to the BSP's "bsp.h" file, or
|
||||
inserted into an application header (e.g. a "network_config.h" file, or
|
||||
similar):
|
||||
|
||||
extern int rtems_dc_driver_attach(struct rtems_bsdnet_ifconfig *, int);
|
||||
#define BSP_DEC_NETWORK_DRIVER_NAME "tl1" /* "tl" as in "tulip-clone" */
|
||||
#define BSP_DEC_NETWORK_DRIVER_ATTACH rtems_dc_driver_attach
|
||||
|
||||
|
||||
**************************
|
||||
Linux Tx ----> RTEMS Rx: *
|
||||
**************************
|
||||
TRANSMITTER:
|
||||
ttcp-t: buflen=8192, nbuf=65536, align=16384/0, port=5001 tcp -> rtems
|
||||
ttcp-t: 536870912 bytes in 45.72 real seconds = 11468.54 KB/sec +++
|
||||
ttcp-t: 536870912 bytes in 6.87 CPU seconds = 76315.57 KB/cpu sec
|
||||
ttcp-t: 65536 I/O calls, msec/call = 0.71, calls/sec = 1433.57
|
||||
ttcp-t: 0.1user 6.7sys 0:45real 15% 0i+0d 0maxrss 0+2pf 0+0csw
|
||||
|
||||
|
||||
RECEIVER:
|
||||
ttcp-r: buflen=8192, nbuf=65536, align=16384/0, port=5001 tcp
|
||||
ttcp-r: 536870912 bytes in 45.72 real seconds = 11467.37 KB/sec +++
|
||||
ttcp-r: 536870912 bytes in 45.87 CPU seconds = 11467.37 KB/cpu sec
|
||||
ttcp-r: 370837 I/O calls, msec/call = 0.13, calls/sec = 8111.05
|
||||
ttcp-r: 0.0user 45.7sys 0:45real 100% 0i+0d 0maxrss 0+0pf 0+0csw
|
||||
|
||||
|
||||
|
||||
**************************
|
||||
RTEMS Tx ----> Linux Rx: *
|
||||
**************************
|
||||
TRANSMITTER:
|
||||
ttcp-t: buflen=8192, nbuf=65536, align=16384/0, port=5001 tcp ->192.168.1.1
|
||||
ttcp-t: 536870912 bytes in 46.22 real seconds = 11343.31 KB/sec +++
|
||||
ttcp-t: 536870912 bytes in 46.22 CPU seconds = 11343.31 KB/cpu sec
|
||||
ttcp-t: 65536 I/O calls, msec/call = 0.72, calls/sec = 1417.91
|
||||
ttcp-t: 0.0user 46.2sys 0:46real 100% 0i+0d 0maxrss 0+0pf 0+0csw
|
||||
|
||||
|
||||
|
||||
|
||||
RECEIVER:
|
||||
ttcp-r: buflen=8192, nbuf=65536, align=16384/0, port=5001 tcp
|
||||
ttcp-r: 536870912 bytes in 46.22 real seconds = 11343.05 KB/sec +++
|
||||
ttcp-r: 536870912 bytes in 11.60 CPU seconds = 45197.24 KB/cpu sec
|
||||
ttcp-r: 356183 I/O calls, msec/call = 0.13, calls/sec = 7706.07
|
||||
ttcp-r: 0.6user 10.9sys 0:46real 25% 0i+0d 0maxrss 0+2pf 0+0csw
|
||||
|
||||
|
||||
|
||||
****************************************************************************
|
||||
****************************************************************************
|
||||
****************************************************************************
|
||||
******************* Test with 40kB buffer size *****************************
|
||||
****************************************************************************
|
||||
****************************************************************************
|
||||
****************************************************************************
|
||||
|
||||
|
||||
**************************
|
||||
RTEMS Tx ----> Linux Rx: *
|
||||
**************************
|
||||
TRANSMITTER:
|
||||
ttcp-t: buflen=40960, nbuf=13107, align=16384/0, port=5001 tcp -> 192.168.1.1
|
||||
ttcp-t: 536862720 bytes in 46.23 real seconds = 11340.69 KB/sec +++
|
||||
ttcp-t: 536862720 bytes in 46.23 CPU seconds = 11340.69 KB/cpu sec
|
||||
ttcp-t: 13107 I/O calls, msec/call = 3.61, calls/sec = 283.52
|
||||
ttcp-t: 0.0user 46.2sys 0:46real 100% 0i+0d 0maxrss 0+0pf 0+0csw
|
||||
|
||||
|
||||
RECEIVER:
|
||||
ttcp-r: buflen=40960, nbuf=13107, align=16384/0, port=5001 tcp
|
||||
ttcp-r: 536862720 bytes in 46.23 real seconds = 11339.54 KB/sec +++
|
||||
ttcp-r: 536862720 bytes in 10.70 CPU seconds = 48998.13 KB/cpu sec
|
||||
ttcp-r: 355970 I/O calls, msec/call = 0.13, calls/sec = 7699.20
|
||||
ttcp-r: 0.5user 10.1sys 0:46real 23% 0i+0d 0maxrss 0+5pf 0+0csw
|
||||
|
||||
|
||||
|
||||
****************************************************************************
|
||||
****************************************************************************
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,510 +0,0 @@
|
||||
/*
|
||||
* RTEMS CS8900 Driver Setup for the DIMM-PC/i386 made by Kontron.
|
||||
*
|
||||
* Port to the DIMM PC copyright (c) 2004 Angelo Fraietta
|
||||
* This project has been assisted by the Commonwealth Government
|
||||
* through the Australia Council, its arts funding and advisory body.
|
||||
*
|
||||
* Port performed by Chris Johns, Cybertec Pty Ltd, Jan 2004.
|
||||
* Based on the Cybertec CS8900 driver setup for the SFP-101.
|
||||
*
|
||||
*/
|
||||
|
||||
#define CS8900_VERBOSE 0
|
||||
#define HAVE_MRB_CS8900_DATA_BUS_SWAPPED 1
|
||||
|
||||
#include <bsp.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/monitor.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
#include <irq.h>
|
||||
|
||||
#include "cs8900.h"
|
||||
|
||||
#include <net/route.h>
|
||||
|
||||
/*
|
||||
* Loopback interface.
|
||||
*/
|
||||
|
||||
extern int rtems_bsdnet_loopattach (struct rtems_bsdnet_ifconfig *, int);
|
||||
|
||||
static struct rtems_bsdnet_ifconfig loopback_config =
|
||||
{
|
||||
"lo0", /* name */
|
||||
rtems_bsdnet_loopattach, /* attach function */
|
||||
NULL, /* link to next interface */
|
||||
"127.0.0.1", /* IP address */
|
||||
"255.0.0.0", /* IP net mask */
|
||||
};
|
||||
|
||||
/*
|
||||
* Network configuration
|
||||
*/
|
||||
|
||||
struct rtems_bsdnet_config rtems_bsdnet_config =
|
||||
{
|
||||
&loopback_config,
|
||||
NULL,
|
||||
20, /* Network task priority */
|
||||
32 * 1024, /* Mbuf capacity */
|
||||
96 * 1024, /* Mbuf cluster capacity */
|
||||
};
|
||||
|
||||
|
||||
static void cs8900_isr ();
|
||||
static void cs8900_int_off (const rtems_irq_connect_data* unused);
|
||||
static void cs8900_int_on (const rtems_irq_connect_data* unused);
|
||||
static int cs8900_int_is_on (const rtems_irq_connect_data *irq);
|
||||
|
||||
/**
|
||||
* The device's data.
|
||||
*/
|
||||
static cs8900_device cs8900;
|
||||
static rtems_irq_connect_data cs8900_irq =
|
||||
{
|
||||
0,
|
||||
cs8900_isr,
|
||||
cs8900_int_on,
|
||||
cs8900_int_off,
|
||||
cs8900_int_is_on
|
||||
};
|
||||
|
||||
#if CS8900_VERBOSE
|
||||
static int cs8900_io_verbose = 1;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Device structure for attaching to the BSD stack.
|
||||
*/
|
||||
static struct rtems_bsdnet_ifconfig cs8900_ifconfig =
|
||||
{
|
||||
"cs0", /* name */
|
||||
cs8900_driver_attach, /* attach funtion */
|
||||
NULL, /* next interface */
|
||||
NULL, /* ip address */
|
||||
NULL, /* ip netmask */
|
||||
NULL, /* hardware address */
|
||||
0, /* ignore broadcast */
|
||||
0, /* mtu */
|
||||
0, /* rbuf count */
|
||||
0, /* xbuf count */
|
||||
0, /* port */
|
||||
0, /* irno */
|
||||
0, /* bpar */
|
||||
0 /* drv ctrl */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Commands to register.
|
||||
*/
|
||||
|
||||
rtems_monitor_command_entry_t rtems_bsdnet_commands[] =
|
||||
{
|
||||
{
|
||||
"ifstats",
|
||||
"Show the interface stats.\n",
|
||||
0,
|
||||
(void*) rtems_bsdnet_show_if_stats,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"ipstats",
|
||||
"Show the IP stats.\n",
|
||||
0,
|
||||
(void*) rtems_bsdnet_show_ip_stats,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"routes",
|
||||
"Show the inet routes.\n",
|
||||
0,
|
||||
(void*) rtems_bsdnet_show_inet_routes,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"mbufs",
|
||||
"Show the mbuf stats.\n",
|
||||
0,
|
||||
(void*) rtems_bsdnet_show_mbuf_stats,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"icmp",
|
||||
"Show the ICMP stats.\n",
|
||||
0,
|
||||
(void*) rtems_bsdnet_show_icmp_stats,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"udp",
|
||||
"Show the UDP stats.\n",
|
||||
0,
|
||||
(void*) rtems_bsdnet_show_udp_stats,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"tcp",
|
||||
"Show the TCP stats.\n",
|
||||
0,
|
||||
(void*) rtems_bsdnet_show_tcp_stats,
|
||||
0,
|
||||
0,
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
cs8900_isr ()
|
||||
{
|
||||
/*
|
||||
* Note: we could have a high priority task here to call the
|
||||
* drivers handler. The would lower the interrupt latancy
|
||||
* we aother wise have.
|
||||
*/
|
||||
cs8900_interrupt (cs8900_irq.name, &cs8900);
|
||||
}
|
||||
|
||||
static void
|
||||
cs8900_int_on (const rtems_irq_connect_data *unused)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
cs8900_int_off (const rtems_irq_connect_data *unused)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
cs8900_int_is_on (const rtems_irq_connect_data *irq)
|
||||
{
|
||||
return BSP_irq_enabled_at_i8259s (irq->name);
|
||||
}
|
||||
|
||||
void cs8900_io_set_reg (cs8900_device *cs, unsigned short reg, unsigned short data)
|
||||
{
|
||||
#if CS8900_VERBOSE
|
||||
if (cs8900_io_verbose)
|
||||
printk ("CS8900: io set reg=0x%04x, data=0x%04x\n", reg, data);
|
||||
#endif
|
||||
outport_word (cs->io_base + reg, data);
|
||||
}
|
||||
|
||||
unsigned short cs8900_io_get_reg (cs8900_device *cs, unsigned short reg)
|
||||
{
|
||||
unsigned short data;
|
||||
inport_word (cs->io_base + reg, data);
|
||||
#if CS8900_VERBOSE
|
||||
if (cs8900_io_verbose)
|
||||
printk ("CS8900: io get reg=0x%04x, data=0x%04x\n", reg, data);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
|
||||
void cs8900_mem_set_reg (cs8900_device *cs, unsigned long reg, unsigned short data)
|
||||
{
|
||||
printk ("CS8900: mem_set_reg register access called. Only IO supported.\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
unsigned short cs8900_mem_get_reg (cs8900_device *cs, unsigned long reg)
|
||||
{
|
||||
printk ("CS8900: mem_get_reg register access called. Only IO supported.\n");
|
||||
while (1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cs8900_put_data_block (cs8900_device *cs, int len, unsigned char *data)
|
||||
{
|
||||
unsigned short *src = (unsigned short *) ((unsigned long) data);
|
||||
|
||||
for (; len > 1; len -= 2)
|
||||
outport_word (cs->io_base, *src++);
|
||||
|
||||
if (len)
|
||||
outport_word (cs->io_base, *src++);
|
||||
}
|
||||
|
||||
unsigned short cs8900_get_data_block (cs8900_device *cs, unsigned char *data)
|
||||
{
|
||||
unsigned short *dst;
|
||||
int cnt;
|
||||
int len;
|
||||
|
||||
/*
|
||||
* Drop the Rx status first.
|
||||
*/
|
||||
inport_word (cs->io_base, len);
|
||||
|
||||
/*
|
||||
* Now the length.
|
||||
*/
|
||||
inport_word (cs->io_base, len);
|
||||
|
||||
dst = (unsigned short *) ((unsigned long) data);
|
||||
cnt = len >> 1;
|
||||
|
||||
while (cnt--)
|
||||
inport_word (cs->io_base, *dst++);
|
||||
|
||||
if (len & 1)
|
||||
inport_word (cs->io_base, *dst++);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
cs8900_tx_load (cs8900_device *cs, struct mbuf *m)
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned char *src = 0;
|
||||
unsigned short *wsrc = 0;
|
||||
unsigned char remainder = 0;
|
||||
unsigned char word[2];
|
||||
|
||||
while (m)
|
||||
{
|
||||
/*
|
||||
* We can get empty mbufs from the stack.
|
||||
*/
|
||||
|
||||
len = m->m_len;
|
||||
src = mtod (m, unsigned char*);
|
||||
|
||||
if (len)
|
||||
{
|
||||
if (remainder)
|
||||
{
|
||||
#if HAVE_MRB_CS8900_DATA_BUS_SWAPPED
|
||||
word[1] = *src++;
|
||||
#else
|
||||
word[0] = *src++;
|
||||
#endif
|
||||
outport_word (cs->io_base, *((unsigned short*) (unsigned long) &word));
|
||||
len--;
|
||||
remainder = 0;
|
||||
}
|
||||
|
||||
if (len & 1)
|
||||
{
|
||||
remainder = 1;
|
||||
len--;
|
||||
}
|
||||
|
||||
wsrc = (unsigned short*) src;
|
||||
|
||||
for (; len; len -= 2, src += 2)
|
||||
outport_word (cs->io_base, *wsrc++);
|
||||
|
||||
if (remainder)
|
||||
#if HAVE_MRB_CS8900_DATA_BUS_SWAPPED
|
||||
word[0] = *src++;
|
||||
#else
|
||||
word[1] = *src++;
|
||||
#endif
|
||||
}
|
||||
|
||||
m = m->m_next;
|
||||
}
|
||||
|
||||
if (remainder)
|
||||
{
|
||||
#if HAVE_MRB_CS8900_DATA_BUS_SWAPPED
|
||||
word[1] = *src++;
|
||||
#else
|
||||
word[0] = *src++;
|
||||
#endif
|
||||
outport_word (cs->io_base, *((unsigned short*) (unsigned long) &word));
|
||||
}
|
||||
}
|
||||
|
||||
void cs8900_attach_interrupt (cs8900_device *cs)
|
||||
{
|
||||
BSP_install_rtems_irq_handler (&cs8900_irq);
|
||||
}
|
||||
|
||||
void cs8900_detach_interrupt (cs8900_device *cs)
|
||||
{
|
||||
BSP_remove_rtems_irq_handler (&cs8900_irq);
|
||||
}
|
||||
|
||||
void
|
||||
BSP_cs8900_attach (unsigned long io_base, unsigned long mem_base, int intrp,
|
||||
const char* ip, const char* nm, const char* gw)
|
||||
{
|
||||
cs8900_device *cs = &cs8900;
|
||||
int flags;
|
||||
struct sockaddr_in address;
|
||||
struct sockaddr_in netmask;
|
||||
struct sockaddr_in broadcast;
|
||||
struct sockaddr_in gateway;
|
||||
int cmd;
|
||||
|
||||
printf ("cso: io=0x%0lx mem=0 irq=%d\n", io_base, intrp);
|
||||
|
||||
memset (cs, 0, sizeof (cs8900));
|
||||
|
||||
cs->dev = 0;
|
||||
cs->rx_queue_size = 30;
|
||||
cs->io_base = io_base;
|
||||
|
||||
if (mem_base)
|
||||
printf ("cs8900: memory mode is currently not supported.\n");
|
||||
|
||||
cs->mem_base = 0;
|
||||
|
||||
switch (intrp)
|
||||
{
|
||||
case 5:
|
||||
cs->irq_level = 3;
|
||||
break;
|
||||
case 10:
|
||||
cs->irq_level = 0;
|
||||
break;
|
||||
case 11:
|
||||
cs->irq_level = 1;
|
||||
break;
|
||||
case 12:
|
||||
cs->irq_level = 2;
|
||||
break;
|
||||
default:
|
||||
printf ("cs8900: unsupported IRQ level\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cs8900_irq.name = intrp;
|
||||
|
||||
/*
|
||||
* Get the MAC adress from the CS8900.
|
||||
*/
|
||||
|
||||
cs8900_get_mac_addr (cs, cs->mac_address);
|
||||
|
||||
/*
|
||||
* Setup the BSD interface configure structure.
|
||||
*/
|
||||
|
||||
cs8900_ifconfig.drv_ctrl = cs;
|
||||
cs8900_ifconfig.hardware_address = cs->mac_address;
|
||||
|
||||
printf ("CS8900 initialisation\n");
|
||||
|
||||
rtems_bsdnet_attach (&cs8900_ifconfig);
|
||||
|
||||
/*
|
||||
* Configure the interface using the boot configuration.
|
||||
*/
|
||||
|
||||
flags = IFF_UP;
|
||||
if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
|
||||
SIOCSIFFLAGS,
|
||||
&flags) < 0)
|
||||
{
|
||||
printf ("error: can't bring up %s: %s\n",
|
||||
cs8900_ifconfig.name, strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ip && strlen (ip) && nm && strlen (nm))
|
||||
{
|
||||
printf ("%s: addr: %s netmask: %s gateway: %s\n",
|
||||
cs8900_ifconfig.name, ip, nm, gw ? gw : "none");
|
||||
|
||||
memset (&netmask, '\0', sizeof netmask);
|
||||
netmask.sin_len = sizeof netmask;
|
||||
netmask.sin_family = AF_INET;
|
||||
|
||||
if (!inet_aton (nm, &netmask.sin_addr))
|
||||
{
|
||||
printf ("error: cannot parse the network mask: %s\n", nm);
|
||||
return;
|
||||
}
|
||||
|
||||
memset (&address, '\0', sizeof address);
|
||||
address.sin_len = sizeof address;
|
||||
address.sin_family = AF_INET;
|
||||
|
||||
if (!inet_aton (ip, &address.sin_addr))
|
||||
{
|
||||
printf ("error: cannot parse the ip address: %s\n", ip);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
|
||||
SIOCSIFNETMASK,
|
||||
&netmask) < 0)
|
||||
{
|
||||
printf ("error: can't set %s netmask: %s\n",
|
||||
cs8900_ifconfig.name, strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
|
||||
SIOCSIFADDR,
|
||||
&address) < 0)
|
||||
{
|
||||
printf ("error: can't set %s address: %s\n",
|
||||
cs8900_ifconfig.name, strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
memset (&broadcast, '\0', sizeof broadcast);
|
||||
broadcast.sin_len = sizeof broadcast;
|
||||
broadcast.sin_family = AF_INET;
|
||||
broadcast.sin_addr.s_addr =
|
||||
(address.sin_addr.s_addr & netmask.sin_addr.s_addr) | ~netmask.sin_addr.s_addr;
|
||||
|
||||
if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
|
||||
SIOCSIFBRDADDR,
|
||||
&broadcast) < 0)
|
||||
{
|
||||
printf ("error: can't set %s broadcast address: %s\n",
|
||||
cs8900_ifconfig.name, strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (gw && strlen (gw))
|
||||
{
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
netmask.sin_addr.s_addr = INADDR_ANY;
|
||||
memset (&gateway, '\0', sizeof gateway);
|
||||
gateway.sin_len = sizeof gateway;
|
||||
gateway.sin_family = AF_INET;
|
||||
|
||||
if (!inet_aton (gw, &gateway.sin_addr))
|
||||
printf ("warning: cannot parse the gateway address: %s\n", ip);
|
||||
else
|
||||
{
|
||||
if (rtems_bsdnet_rtrequest (RTM_ADD,
|
||||
(struct sockaddr *) &address,
|
||||
(struct sockaddr *) &gateway,
|
||||
(struct sockaddr *) &netmask,
|
||||
(RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL) < 0)
|
||||
printf ("error: can't set default route: %s\n", strerror (errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rtems_bsdnet_do_bootp_and_rootfs ();
|
||||
}
|
||||
|
||||
for (cmd = 0;
|
||||
cmd < sizeof (rtems_bsdnet_commands) / sizeof (rtems_monitor_command_entry_t);
|
||||
cmd++)
|
||||
rtems_monitor_insert_cmd (&rtems_bsdnet_commands[cmd]);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* RTEMS CS8900 Driver Setup for the DIMM-PC/i386 made by Kontron.
|
||||
*
|
||||
* Port to the DIMM PC copyright (c) 2004 Angelo Fraietta
|
||||
* This project has been assisted by the Commonwealth Government
|
||||
* through the Australia Council, its arts funding and advisory body.
|
||||
*
|
||||
* Port performed by Chris Johns, Cybertec Pty Ltd, Jan 2004.
|
||||
* Based on the Cybertec CS8900 driver setup for the SFP-101.
|
||||
*/
|
||||
|
||||
#if !defined (__BSP_CS8900_H__)
|
||||
#define __BSP_CS8900_H__
|
||||
|
||||
/**
|
||||
* BSP CS8900 Device initialisation and interface attach.
|
||||
*
|
||||
* @param io_base The I/O base address of the device.
|
||||
*
|
||||
* @param mem_base The memory base address. Currently not used.
|
||||
*
|
||||
* @param intrp The ISA bus IRQ. These are currently limited to
|
||||
* 5, 10, 11, and 12 as documented in the CS8900
|
||||
* manual.
|
||||
*
|
||||
* @param ip IP address in ASCII. For example 10.10.10.10. If the
|
||||
* pointer is a NULL (0) the interface will BOOTP.
|
||||
*
|
||||
* @param nm Network Mask in ASCII. For example 10.10.10.255.
|
||||
*
|
||||
* @param gw Address of the gateway machine. For example
|
||||
* 10.10.10.1.
|
||||
*/
|
||||
|
||||
void BSP_cs8900_attach (unsigned long io_base, unsigned long mem_base, int intrp,
|
||||
const char* ip, const char* nm, const char* gw);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,448 +0,0 @@
|
||||
/* $NetBSD: i82586reg.h,v 1.7 1998/02/28 01:07:45 pk Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Paul Kranenburg.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, University of Vermont and State Agricultural College.
|
||||
* Copyright (c) 1992, Garrett A. Wollman.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* Vermont and State Agricultural College and Garrett A. Wollman.
|
||||
* 4. Neither the name of the University nor the name of the author
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHOR BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Intel 82586 Ethernet chip
|
||||
* Register, bit, and structure definitions.
|
||||
*
|
||||
* Written by GAW with reference to the Clarkson Packet Driver code for this
|
||||
* chip written by Russ Nelson and others.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE, the structure definitions in here are for reference only.
|
||||
* We use integer offsets exclusively to access the i82586 data structures.
|
||||
*/
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* This is the master configuration block.
|
||||
* It tells the hardware where all the rest of the stuff is.
|
||||
*/
|
||||
struct __ie_sys_conf_ptr {
|
||||
u_int16_t mbz; /* must be zero */
|
||||
u_int8_t ie_bus_use; /* true if 8-bit only */
|
||||
u_int8_t mbz2[5]; /* must be zero */
|
||||
u_int32_t ie_iscp_ptr; /* 24-bit physaddr of ISCP */
|
||||
};
|
||||
#endif
|
||||
#define IE_SCP_SZ 12
|
||||
#define IE_SCP_BUS_USE(base) ((base) + 2)
|
||||
#define IE_SCP_ISCP(base) ((base) + 8)
|
||||
|
||||
/*
|
||||
* Note that this is wired in hardware; the SCP is always located here, no
|
||||
* matter what.
|
||||
*/
|
||||
#define IE_SCP_ADDR 0xfffff4
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* The tells the hardware where all the rest of the stuff is, too.
|
||||
* FIXME: some of these should be re-commented after we figure out their
|
||||
* REAL function.
|
||||
*/
|
||||
struct __ie_int_sys_conf_ptr {
|
||||
u_int8_t ie_busy; // zeroed after init
|
||||
u_int8_t mbz;
|
||||
u_int16_t ie_scb_offset; // 16-bit physaddr of next struct
|
||||
caddr_t ie_base; // 24-bit physaddr for all 16-bit vars
|
||||
};
|
||||
#endif
|
||||
#define IE_ISCP_SZ 8
|
||||
#define IE_ISCP_BUSY(base) ((base) + 0)
|
||||
#define IE_ISCP_SCB(base) ((base) + 2)
|
||||
#define IE_ISCP_BASE(base) ((base) + 4)
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* This FINALLY tells the hardware what to do and where to put it.
|
||||
*/
|
||||
struct __ie_sys_ctl_block {
|
||||
u_int16_t ie_status; // status word
|
||||
u_int16_t ie_command; // command word
|
||||
u_int16_t ie_command_list; // 16-pointer to command block list
|
||||
u_int16_t ie_recv_list; // 16-pointer to receive frame list
|
||||
u_int16_t ie_err_crc; // CRC errors
|
||||
u_int16_t ie_err_align; // Alignment errors
|
||||
u_int16_t ie_err_resource; // Resource errors
|
||||
u_int16_t ie_err_overrun; // Overrun errors
|
||||
};
|
||||
#endif
|
||||
#define IE_SCB_SZ 16
|
||||
#define IE_SCB_STATUS(base) ((base) + 0)
|
||||
#define IE_SCB_CMD(base) ((base) + 2)
|
||||
#define IE_SCB_CMDLST(base) ((base) + 4)
|
||||
#define IE_SCB_RCVLST(base) ((base) + 6)
|
||||
#define IE_SCB_ERRCRC(base) ((base) + 8)
|
||||
#define IE_SCB_ERRALN(base) ((base) + 10)
|
||||
#define IE_SCB_ERRRES(base) ((base) + 12)
|
||||
#define IE_SCB_ERROVR(base) ((base) + 14)
|
||||
|
||||
/* Command values */
|
||||
#define IE_RUC_MASK 0x0070 /* mask for RU command */
|
||||
#define IE_RUC_NOP 0 /* for completeness */
|
||||
#define IE_RUC_START 0x0010 /* start receive unit command */
|
||||
#define IE_RUC_RESUME 0x0020 /* resume a suspended receiver command */
|
||||
#define IE_RUC_SUSPEND 0x0030 /* suspend receiver command */
|
||||
#define IE_RUC_ABORT 0x0040 /* abort current receive operation */
|
||||
|
||||
#define IE_CUC_MASK 0x0700 /* mask for CU command */
|
||||
#define IE_CUC_NOP 0 /* included for completeness */
|
||||
#define IE_CUC_START 0x0100 /* do-command command */
|
||||
#define IE_CUC_RESUME 0x0200 /* resume a suspended cmd list */
|
||||
#define IE_CUC_SUSPEND 0x0300 /* suspend current command */
|
||||
#define IE_CUC_ABORT 0x0400 /* abort current command */
|
||||
|
||||
#define IE_ACK_COMMAND 0xf000 /* mask for ACK command */
|
||||
#define IE_ACK_CX 0x8000 /* ack IE_ST_CX */
|
||||
#define IE_ACK_FR 0x4000 /* ack IE_ST_FR */
|
||||
#define IE_ACK_CNA 0x2000 /* ack IE_ST_CNA */
|
||||
#define IE_ACK_RNR 0x1000 /* ack IE_ST_RNR */
|
||||
|
||||
#define IE_ACTION_COMMAND(x) (((x) & IE_CUC_MASK) == IE_CUC_START)
|
||||
/* is this command an action command? */
|
||||
|
||||
/* Status values */
|
||||
#define IE_ST_WHENCE 0xf000 /* mask for cause of interrupt */
|
||||
#define IE_ST_CX 0x8000 /* command with I bit completed */
|
||||
#define IE_ST_FR 0x4000 /* frame received */
|
||||
#define IE_ST_CNA 0x2000 /* all commands completed */
|
||||
#define IE_ST_RNR 0x1000 /* receive not ready */
|
||||
|
||||
#define IE_CUS_MASK 0x0700 /* mask for command unit status */
|
||||
#define IE_CUS_ACTIVE 0x0200 /* command unit is active */
|
||||
#define IE_CUS_SUSPEND 0x0100 /* command unit is suspended */
|
||||
|
||||
#define IE_RUS_MASK 0x0070 /* mask for receiver unit status */
|
||||
#define IE_RUS_SUSPEND 0x0010 /* receiver is suspended */
|
||||
#define IE_RUS_NOSPACE 0x0020 /* receiver has no resources */
|
||||
#define IE_RUS_READY 0x0040 /* receiver is ready */
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* This is filled in partially by the chip, partially by us.
|
||||
*/
|
||||
struct __ie_recv_frame_desc {
|
||||
u_int16_t ie_fd_status; // status for this frame
|
||||
u_int16_t ie_fd_last; // end of frame list flag
|
||||
u_int16_t ie_fd_next; // 16-pointer to next RFD
|
||||
u_int16_t ie_fd_buf_desc; // 16-pointer to list of buffer descs
|
||||
struct __ie_en_addr dest; // destination ether
|
||||
struct __ie_en_addr src; // source ether
|
||||
u_int16_t ie_length; // 802 length/Ether type
|
||||
u_short mbz; // must be zero
|
||||
};
|
||||
#endif
|
||||
#define IE_RFRAME_SZ 24
|
||||
#define IE_RFRAME_ADDR(base,i) ((base) + (i) * IE_RFRAME_SZ)
|
||||
#define IE_RFRAME_STATUS(b,i) (IE_RFRAME_ADDR(b,i) + 0)
|
||||
#define IE_RFRAME_LAST(b,i) (IE_RFRAME_ADDR(b,i) + 2)
|
||||
#define IE_RFRAME_NEXT(b,i) (IE_RFRAME_ADDR(b,i) + 4)
|
||||
#define IE_RFRAME_BUFDESC(b,i) (IE_RFRAME_ADDR(b,i) + 6)
|
||||
#define IE_RFRAME_EDST(b,i) (IE_RFRAME_ADDR(b,i) + 8)
|
||||
#define IE_RFRAME_ESRC(b,i) (IE_RFRAME_ADDR(b,i) + 14)
|
||||
#define IE_RFRAME_ELEN(b,i) (IE_RFRAME_ADDR(b,i) + 20)
|
||||
|
||||
/* "last" bits */
|
||||
#define IE_FD_EOL 0x8000 /* last rfd in list */
|
||||
#define IE_FD_SUSP 0x4000 /* suspend RU after receipt */
|
||||
|
||||
/* status field bits */
|
||||
#define IE_FD_COMPLETE 0x8000 /* frame is complete */
|
||||
#define IE_FD_BUSY 0x4000 /* frame is busy */
|
||||
#define IE_FD_OK 0x2000 /* frame is ok */
|
||||
#define IE_FD_CRC 0x0800 /* CRC error */
|
||||
#define IE_FD_ALGN 0x0400 /* Alignment error */
|
||||
#define IE_FD_RNR 0x0200 /* receiver out of resources here */
|
||||
#define IE_FD_OVR 0x0100 /* DMA overrun */
|
||||
#define IE_FD_SHORT 0x0080 /* Short frame */
|
||||
#define IE_FD_NOEOF 0x0040 /* no EOF (?) */
|
||||
#define IE_FD_ERRMASK /* all error bits */ \
|
||||
(IE_FD_CRC|IE_FD_ALGN|IE_FD_RNR|IE_FD_OVR|IE_FD_SHORT|IE_FD_NOEOF)
|
||||
#define IE_FD_STATUSBITS \
|
||||
"\20\20COMPLT\17BUSY\16OK\14CRC\13ALGN\12RNR\11OVR\10SHORT\7NOEOF"
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* linked list of buffers...
|
||||
*/
|
||||
struct __ie_recv_buf_desc {
|
||||
u_int16_t ie_rbd_status; // status for this buffer
|
||||
u_int16_t ie_rbd_next; // 16-pointer to next RBD
|
||||
caddr_t ie_rbd_buffer; // 24-pointer to buffer for this RBD
|
||||
u_int16_t ie_rbd_length; // length of the buffer
|
||||
u_int16_t mbz; // must be zero
|
||||
};
|
||||
#endif
|
||||
#define IE_RBD_SZ 12
|
||||
#define IE_RBD_ADDR(base,i) ((base) + (i) * IE_RBD_SZ)
|
||||
#define IE_RBD_STATUS(b,i) (IE_RBD_ADDR(b,i) + 0)
|
||||
#define IE_RBD_NEXT(b,i) (IE_RBD_ADDR(b,i) + 2)
|
||||
#define IE_RBD_BUFADDR(b,i) (IE_RBD_ADDR(b,i) + 4)
|
||||
#define IE_RBD_BUFLEN(b,i) (IE_RBD_ADDR(b,i) + 8)
|
||||
|
||||
/* RBD status fields */
|
||||
#define IE_RBD_LAST 0x8000 /* last buffer */
|
||||
#define IE_RBD_USED 0x4000 /* this buffer has data */
|
||||
#define IE_RBD_CNTMASK 0x3fff /* byte count of buffer data */
|
||||
|
||||
/* RDB `End Of List' flag; encoded in `buffer length' field */
|
||||
#define IE_RBD_EOL 0x8000 /* last buffer */
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* All commands share this in common.
|
||||
*/
|
||||
struct __ie_cmd_common {
|
||||
u_int16_t ie_cmd_status; // status of this command
|
||||
u_int16_t ie_cmd_cmd; // command word
|
||||
u_int16_t ie_cmd_link; // link to next command
|
||||
};
|
||||
#endif
|
||||
#define IE_CMD_COMMON_SZ 6
|
||||
#define IE_CMD_COMMON_STATUS(base) ((base) + 0)
|
||||
#define IE_CMD_COMMON_CMD(base) ((base) + 2)
|
||||
#define IE_CMD_COMMON_LINK(base) ((base) + 4)
|
||||
|
||||
#define IE_STAT_COMPL 0x8000 /* command is completed */
|
||||
#define IE_STAT_BUSY 0x4000 /* command is running now */
|
||||
#define IE_STAT_OK 0x2000 /* command completed successfully */
|
||||
#define IE_STAT_ABORT 0x1000 /* command was aborted */
|
||||
|
||||
#define IE_CMD_NOP 0x0000 /* NOP */
|
||||
#define IE_CMD_IASETUP 0x0001 /* initial address setup */
|
||||
#define IE_CMD_CONFIG 0x0002 /* configure command */
|
||||
#define IE_CMD_MCAST 0x0003 /* multicast setup command */
|
||||
#define IE_CMD_XMIT 0x0004 /* transmit command */
|
||||
#define IE_CMD_TDR 0x0005 /* time-domain reflectometer command */
|
||||
#define IE_CMD_DUMP 0x0006 /* dump command */
|
||||
#define IE_CMD_DIAGNOSE 0x0007 /* diagnostics command */
|
||||
|
||||
#define IE_CMD_LAST 0x8000 /* this is the last command in the list */
|
||||
#define IE_CMD_SUSPEND 0x4000 /* suspend CU after this command */
|
||||
#define IE_CMD_INTR 0x2000 /* post an interrupt after completion */
|
||||
|
||||
/*
|
||||
* No-op commands; just like COMMON but "indexable"
|
||||
*/
|
||||
#define IE_CMD_NOP_SZ IE_CMD_COMMON_SZ
|
||||
#define IE_CMD_NOP_ADDR(base,i) ((base) + (i) * IE_CMD_NOP_SZ)
|
||||
#define IE_CMD_NOP_STATUS(b,i) (IE_CMD_NOP_ADDR(b,i) + 0)
|
||||
#define IE_CMD_NOP_CMD(b,i) (IE_CMD_NOP_ADDR(b,i) + 2)
|
||||
#define IE_CMD_NOP_LINK(b,i) (IE_CMD_NOP_ADDR(b,i) + 4)
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* This is the command to transmit a frame.
|
||||
*/
|
||||
struct __ie_xmit_cmd {
|
||||
struct __ie_cmd_common com; // common part
|
||||
#define __ie_xmit_status com.ie_cmd_status
|
||||
|
||||
u_int16_t ie_xmit_desc; // pointer to buffer descriptor
|
||||
struct __ie_en_addr ie_xmit_addr; // destination address
|
||||
u_int16_t ie_xmit_length; // 802.3 length/Ether type field
|
||||
};
|
||||
#endif
|
||||
#define IE_CMD_XMIT_SZ (IE_CMD_COMMON_SZ + 10)
|
||||
#define IE_CMD_XMIT_ADDR(base,i) ((base) + (i) * IE_CMD_XMIT_SZ)
|
||||
#define IE_CMD_XMIT_STATUS(b,i) \
|
||||
(IE_CMD_XMIT_ADDR(b,i) + 0) /* == CMD_COMMON_STATUS */
|
||||
#define IE_CMD_XMIT_CMD(b,i) \
|
||||
(IE_CMD_XMIT_ADDR(b,i) + 2) /* == CMD_COMMON_CMD */
|
||||
#define IE_CMD_XMIT_LINK(b,i) \
|
||||
(IE_CMD_XMIT_ADDR(b,i) + 4) /* == CMD_COMMON_LINK */
|
||||
#define IE_CMD_XMIT_DESC(b,i) \
|
||||
(IE_CMD_XMIT_ADDR(b,i) + IE_CMD_COMMON_SZ + 0)
|
||||
#define IE_CMD_XMIT_EADDR(b,i) \
|
||||
(IE_CMD_XMIT_ADDR(b,i) + IE_CMD_COMMON_SZ + 2)
|
||||
#define IE_CMD_XMIT_LEN(b,i) \
|
||||
(IE_CMD_XMIT_ADDR(b,i) + IE_CMD_COMMON_SZ + 8)
|
||||
|
||||
#define IE_XS_MAXCOLL 0x000f /* number of collisions during transmit */
|
||||
#define IE_XS_EXCMAX 0x0020 /* exceeded maximum number of collisions */
|
||||
#define IE_XS_SQE 0x0040 /* SQE positive */
|
||||
#define IE_XS_DEFERRED 0x0080 /* transmission deferred */
|
||||
#define IE_XS_UNDERRUN 0x0100 /* DMA underrun */
|
||||
#define IE_XS_LOSTCTS 0x0200 /* Lost CTS */
|
||||
#define IE_XS_NOCARRIER 0x0400 /* No Carrier */
|
||||
#define IE_XS_LATECOLL 0x0800 /* Late collision */
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* This is a buffer descriptor for a frame to be transmitted.
|
||||
*/
|
||||
struct __ie_xmit_buf {
|
||||
u_int16_t ie_xmit_flags; // see below
|
||||
u_int16_t ie_xmit_next; // 16-pointer to next desc
|
||||
caddr_t ie_xmit_buf; // 24-pointer to the actual buffer
|
||||
};
|
||||
#endif
|
||||
#define IE_XBD_SZ 8
|
||||
#define IE_XBD_ADDR(base,i) ((base) + (i) * IE_XBD_SZ)
|
||||
#define IE_XBD_FLAGS(b,i) (IE_XBD_ADDR(b,i) + 0)
|
||||
#define IE_XBD_NEXT(b,i) (IE_XBD_ADDR(b,i) + 2)
|
||||
#define IE_XBD_BUF(b,i) (IE_XBD_ADDR(b,i) + 4)
|
||||
|
||||
#define IE_TBD_EOL 0x8000 /* this TBD is the last one */
|
||||
#define IE_TBD_CNTMASK 0x3fff /* The rest of the `flags' word
|
||||
is actually the length. */
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Multicast setup command.
|
||||
*/
|
||||
struct __ie_mcast_cmd {
|
||||
struct __ie_cmd_common com; // common part
|
||||
#define ie_mcast_status com.ie_cmd_status
|
||||
|
||||
// size (in bytes) of multicast addresses
|
||||
u_short ie_mcast_bytes;
|
||||
struct __ie_en_addr ie_mcast_addrs[IE_MAXMCAST + 1];// space for them
|
||||
};
|
||||
#endif
|
||||
#define IE_CMD_MCAST_SZ (IE_CMD_COMMON_SZ + 2 /* + XXX */)
|
||||
#define IE_CMD_MCAST_BYTES(base) ((base) + IE_CMD_COMMON_SZ + 0)
|
||||
#define IE_CMD_MCAST_MADDR(base) ((base) + IE_CMD_COMMON_SZ + 2)
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Time Domain Reflectometer command.
|
||||
*/
|
||||
struct __ie_tdr_cmd {
|
||||
struct __ie_cmd_common com; // common part
|
||||
#define ie_tdr_status com.ie_cmd_status
|
||||
u_short ie_tdr_time; // error bits and time
|
||||
};
|
||||
#endif
|
||||
#define IE_CMD_TDR_SZ (IE_CMD_COMMON_SZ + 2)
|
||||
#define IE_CMD_TDR_TIME(base) ((base) + IE_CMD_COMMON_SZ + 0)
|
||||
|
||||
#define IE_TDR_SUCCESS 0x8000 /* TDR succeeded without error */
|
||||
#define IE_TDR_XCVR 0x4000 /* detected a transceiver problem */
|
||||
#define IE_TDR_OPEN 0x2000 /* detected an incorrect termination ("open") */
|
||||
#define IE_TDR_SHORT 0x1000 /* TDR detected a short circuit */
|
||||
#define IE_TDR_TIME 0x07ff /* mask for reflection time */
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Initial Address Setup command
|
||||
*/
|
||||
struct __ie_iasetup_cmd {
|
||||
struct __ie_cmd_common com;
|
||||
#define ie_iasetup_status com.ie_cmd_status
|
||||
struct __ie_en_addr ie_address;
|
||||
};
|
||||
#endif
|
||||
#define IE_CMD_IAS_SZ (IE_CMD_COMMON_SZ + 6)
|
||||
#define IE_CMD_IAS_EADDR(base) ((base) + IE_CMD_COMMON_SZ + 0)
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Configuration command
|
||||
*/
|
||||
struct __ie_config_cmd {
|
||||
struct __ie_cmd_common com; // common part
|
||||
#define ie_config_status com.ie_cmd_status
|
||||
|
||||
u_int8_t ie_config_count; // byte count (0x0c)
|
||||
u_int8_t ie_fifo; // fifo (8)
|
||||
u_int8_t ie_save_bad; // save bad frames (0x40)
|
||||
u_int8_t ie_addr_len; // address length (0x2e) (AL-LOC == 1)
|
||||
u_int8_t ie_priority; // priority and backoff (0x0)
|
||||
u_int8_t ie_ifs; // inter-frame spacing (0x60)
|
||||
u_int8_t ie_slot_low; // slot time, LSB (0x0)
|
||||
u_int8_t ie_slot_high; // slot time, MSN, and retries (0xf2)
|
||||
u_int8_t ie_promisc; // 1 if promiscuous, else 0
|
||||
u_int8_t ie_crs_cdt; // CSMA/CD parameters (0x0)
|
||||
u_int8_t ie_min_len; // min frame length (0x40)
|
||||
u_int8_t ie_junk; // stuff for 82596 (0xff)
|
||||
};
|
||||
#endif
|
||||
#define IE_CMD_CFG_SZ (IE_CMD_COMMON_SZ + 12)
|
||||
#define IE_CMD_CFG_CNT(base) ((base) + IE_CMD_COMMON_SZ + 0)
|
||||
#define IE_CMD_CFG_FIFO(base) ((base) + IE_CMD_COMMON_SZ + 1)
|
||||
#define IE_CMD_CFG_SAVEBAD(base) ((base) + IE_CMD_COMMON_SZ + 2)
|
||||
#define IE_CMD_CFG_ADDRLEN(base) ((base) + IE_CMD_COMMON_SZ + 3)
|
||||
#define IE_CMD_CFG_PRIORITY(base) ((base) + IE_CMD_COMMON_SZ + 4)
|
||||
#define IE_CMD_CFG_IFS(base) ((base) + IE_CMD_COMMON_SZ + 5)
|
||||
#define IE_CMD_CFG_SLOT_LOW(base) ((base) + IE_CMD_COMMON_SZ + 6)
|
||||
#define IE_CMD_CFG_SLOT_HIGH(base) ((base) + IE_CMD_COMMON_SZ + 7)
|
||||
#define IE_CMD_CFG_PROMISC(base) ((base) + IE_CMD_COMMON_SZ + 8)
|
||||
#define IE_CMD_CFG_CRSCDT(base) ((base) + IE_CMD_COMMON_SZ + 9)
|
||||
#define IE_CMD_CFG_MINLEN(base) ((base) + IE_CMD_COMMON_SZ + 10)
|
||||
#define IE_CMD_CFG_JUNK(base) ((base) + IE_CMD_COMMON_SZ + 11)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,370 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1995, David Greenman
|
||||
* Copyright (c) 2001 Jonathan Lemon <jlemon@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice unmodified, this list of conditions, and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/fxp/if_fxpreg.h,v 1.23.2.4 2001/08/31 02:17:02 jlemon Exp $
|
||||
*/
|
||||
|
||||
#define FXP_VENDORID_INTEL 0x8086
|
||||
|
||||
#define FXP_PCI_MMBA 0x10
|
||||
#define FXP_PCI_IOBA 0x14
|
||||
|
||||
/*
|
||||
* Control/status registers.
|
||||
*/
|
||||
#define FXP_CSR_SCB_RUSCUS 0 /* scb_rus/scb_cus (1 byte) */
|
||||
#define FXP_CSR_SCB_STATACK 1 /* scb_statack (1 byte) */
|
||||
#define FXP_CSR_SCB_COMMAND 2 /* scb_command (1 byte) */
|
||||
#define FXP_CSR_SCB_INTRCNTL 3 /* scb_intrcntl (1 byte) */
|
||||
#define FXP_CSR_SCB_GENERAL 4 /* scb_general (4 bytes) */
|
||||
#define FXP_CSR_PORT 8 /* port (4 bytes) */
|
||||
#define FXP_CSR_FLASHCONTROL 12 /* flash control (2 bytes) */
|
||||
#define FXP_CSR_EEPROMCONTROL 14 /* eeprom control (2 bytes) */
|
||||
#define FXP_CSR_MDICONTROL 16 /* mdi control (4 bytes) */
|
||||
#define FXP_CSR_FLOWCONTROL 0x19 /* flow control (2 bytes) */
|
||||
#define FXP_CSR_GENCONTROL 0x1C /* general control (1 byte) */
|
||||
|
||||
/*
|
||||
* FOR REFERENCE ONLY, the old definition of FXP_CSR_SCB_RUSCUS:
|
||||
*
|
||||
* volatile u_int8_t :2,
|
||||
* scb_rus:4,
|
||||
* scb_cus:2;
|
||||
*/
|
||||
|
||||
#define FXP_PORT_SOFTWARE_RESET 0
|
||||
#define FXP_PORT_SELFTEST 1
|
||||
#define FXP_PORT_SELECTIVE_RESET 2
|
||||
#define FXP_PORT_DUMP 3
|
||||
|
||||
#define FXP_SCB_RUS_IDLE 0
|
||||
#define FXP_SCB_RUS_SUSPENDED 1
|
||||
#define FXP_SCB_RUS_NORESOURCES 2
|
||||
#define FXP_SCB_RUS_READY 4
|
||||
#define FXP_SCB_RUS_SUSP_NORBDS 9
|
||||
#define FXP_SCB_RUS_NORES_NORBDS 10
|
||||
#define FXP_SCB_RUS_READY_NORBDS 12
|
||||
|
||||
#define FXP_SCB_CUS_IDLE 0
|
||||
#define FXP_SCB_CUS_SUSPENDED 1
|
||||
#define FXP_SCB_CUS_ACTIVE 2
|
||||
|
||||
#define FXP_SCB_INTR_DISABLE 0x01 /* Disable all interrupts */
|
||||
#define FXP_SCB_INTR_SWI 0x02 /* Generate SWI */
|
||||
#define FXP_SCB_INTMASK_FCP 0x04
|
||||
#define FXP_SCB_INTMASK_ER 0x08
|
||||
#define FXP_SCB_INTMASK_RNR 0x10
|
||||
#define FXP_SCB_INTMASK_CNA 0x20
|
||||
#define FXP_SCB_INTMASK_FR 0x40
|
||||
#define FXP_SCB_INTMASK_CXTNO 0x80
|
||||
|
||||
#define FXP_SCB_STATACK_FCP 0x01 /* Flow Control Pause */
|
||||
#define FXP_SCB_STATACK_ER 0x02 /* Early Receive */
|
||||
#define FXP_SCB_STATACK_SWI 0x04
|
||||
#define FXP_SCB_STATACK_MDI 0x08
|
||||
#define FXP_SCB_STATACK_RNR 0x10
|
||||
#define FXP_SCB_STATACK_CNA 0x20
|
||||
#define FXP_SCB_STATACK_FR 0x40
|
||||
#define FXP_SCB_STATACK_CXTNO 0x80
|
||||
|
||||
#define FXP_SCB_COMMAND_CU_NOP 0x00
|
||||
#define FXP_SCB_COMMAND_CU_START 0x10
|
||||
#define FXP_SCB_COMMAND_CU_RESUME 0x20
|
||||
#define FXP_SCB_COMMAND_CU_DUMP_ADR 0x40
|
||||
#define FXP_SCB_COMMAND_CU_DUMP 0x50
|
||||
#define FXP_SCB_COMMAND_CU_BASE 0x60
|
||||
#define FXP_SCB_COMMAND_CU_DUMPRESET 0x70
|
||||
|
||||
#define FXP_SCB_COMMAND_RU_NOP 0
|
||||
#define FXP_SCB_COMMAND_RU_START 1
|
||||
#define FXP_SCB_COMMAND_RU_RESUME 2
|
||||
#define FXP_SCB_COMMAND_RU_ABORT 4
|
||||
#define FXP_SCB_COMMAND_RU_LOADHDS 5
|
||||
#define FXP_SCB_COMMAND_RU_BASE 6
|
||||
#define FXP_SCB_COMMAND_RU_RBDRESUME 7
|
||||
|
||||
/*
|
||||
* Command block definitions
|
||||
*/
|
||||
struct fxp_cb_nop {
|
||||
void *fill[2];
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
};
|
||||
struct fxp_cb_ias {
|
||||
void *fill[2];
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
volatile u_int8_t macaddr[6];
|
||||
};
|
||||
/* I hate bit-fields :-( */
|
||||
struct fxp_cb_config {
|
||||
void *fill[2];
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
volatile u_int byte_count:6,
|
||||
:2;
|
||||
volatile u_int rx_fifo_limit:4,
|
||||
tx_fifo_limit:3,
|
||||
:1;
|
||||
volatile u_int8_t adaptive_ifs;
|
||||
volatile u_int mwi_enable:1, /* 8,9 */
|
||||
type_enable:1, /* 8,9 */
|
||||
read_align_en:1, /* 8,9 */
|
||||
end_wr_on_cl:1, /* 8,9 */
|
||||
:4;
|
||||
volatile u_int rx_dma_bytecount:7,
|
||||
:1;
|
||||
volatile u_int tx_dma_bytecount:7,
|
||||
dma_mbce:1;
|
||||
volatile u_int late_scb:1, /* 7 */
|
||||
direct_dma_dis:1, /* 8,9 */
|
||||
tno_int_or_tco_en:1, /* 7,9 */
|
||||
ci_int:1,
|
||||
ext_txcb_dis:1, /* 8,9 */
|
||||
ext_stats_dis:1, /* 8,9 */
|
||||
keep_overrun_rx:1,
|
||||
save_bf:1;
|
||||
volatile u_int disc_short_rx:1,
|
||||
underrun_retry:2,
|
||||
:3,
|
||||
two_frames:1, /* 8,9 */
|
||||
dyn_tbd:1; /* 8,9 */
|
||||
volatile u_int mediatype:1, /* 7 */
|
||||
:6,
|
||||
csma_dis:1; /* 8,9 */
|
||||
volatile u_int tcp_udp_cksum:1, /* 9 */
|
||||
:3,
|
||||
vlan_tco:1, /* 8,9 */
|
||||
link_wake_en:1, /* 8,9 */
|
||||
arp_wake_en:1, /* 8 */
|
||||
mc_wake_en:1; /* 8 */
|
||||
volatile u_int :3,
|
||||
nsai:1,
|
||||
preamble_length:2,
|
||||
loopback:2;
|
||||
volatile u_int linear_priority:3, /* 7 */
|
||||
:5;
|
||||
volatile u_int linear_pri_mode:1, /* 7 */
|
||||
:3,
|
||||
interfrm_spacing:4;
|
||||
volatile u_int :8;
|
||||
volatile u_int :8;
|
||||
volatile u_int promiscuous:1,
|
||||
bcast_disable:1,
|
||||
wait_after_win:1, /* 8,9 */
|
||||
:1,
|
||||
ignore_ul:1, /* 8,9 */
|
||||
crc16_en:1, /* 9 */
|
||||
:1,
|
||||
crscdt:1;
|
||||
volatile u_int fc_delay_lsb:8; /* 8,9 */
|
||||
volatile u_int fc_delay_msb:8; /* 8,9 */
|
||||
volatile u_int stripping:1,
|
||||
padding:1,
|
||||
rcv_crc_xfer:1,
|
||||
long_rx_en:1, /* 8,9 */
|
||||
pri_fc_thresh:3, /* 8,9 */
|
||||
:1;
|
||||
volatile u_int ia_wake_en:1, /* 8 */
|
||||
magic_pkt_dis:1, /* 8,9,!9ER */
|
||||
tx_fc_dis:1, /* 8,9 */
|
||||
rx_fc_restop:1, /* 8,9 */
|
||||
rx_fc_restart:1, /* 8,9 */
|
||||
fc_filter:1, /* 8,9 */
|
||||
force_fdx:1,
|
||||
fdx_pin_en:1;
|
||||
volatile u_int :5,
|
||||
pri_fc_loc:1, /* 8,9 */
|
||||
multi_ia:1,
|
||||
:1;
|
||||
volatile u_int :3,
|
||||
mc_all:1,
|
||||
:4;
|
||||
};
|
||||
|
||||
#define MAXMCADDR 80
|
||||
struct fxp_cb_mcs {
|
||||
struct fxp_cb_tx *next;
|
||||
struct mbuf *mb_head;
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
volatile u_int16_t mc_cnt;
|
||||
volatile u_int8_t mc_addr[MAXMCADDR][6];
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of DMA segments in a TxCB. Note that this is carefully
|
||||
* chosen to make the total struct size an even power of two. It's
|
||||
* critical that no TxCB be split across a page boundry since
|
||||
* no attempt is made to allocate physically contiguous memory.
|
||||
*
|
||||
*/
|
||||
#ifdef __alpha__ /* XXX - should be conditional on pointer size */
|
||||
#define FXP_NTXSEG 28
|
||||
#else
|
||||
#define FXP_NTXSEG 29
|
||||
#endif
|
||||
|
||||
struct fxp_tbd {
|
||||
volatile u_int32_t tb_addr;
|
||||
volatile u_int32_t tb_size;
|
||||
};
|
||||
struct fxp_cb_tx {
|
||||
struct fxp_cb_tx *next;
|
||||
struct mbuf *mb_head;
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
volatile u_int32_t tbd_array_addr;
|
||||
volatile u_int16_t byte_count;
|
||||
volatile u_int8_t tx_threshold;
|
||||
volatile u_int8_t tbd_number;
|
||||
/*
|
||||
* The following structure isn't actually part of the TxCB,
|
||||
* unless the extended TxCB feature is being used. In this
|
||||
* case, the first two elements of the structure below are
|
||||
* fetched along with the TxCB.
|
||||
*/
|
||||
volatile struct fxp_tbd tbd[FXP_NTXSEG];
|
||||
};
|
||||
|
||||
/*
|
||||
* Control Block (CB) definitions
|
||||
*/
|
||||
|
||||
/* status */
|
||||
#define FXP_CB_STATUS_OK 0x2000
|
||||
#define FXP_CB_STATUS_C 0x8000
|
||||
/* commands */
|
||||
#define FXP_CB_COMMAND_NOP 0x0
|
||||
#define FXP_CB_COMMAND_IAS 0x1
|
||||
#define FXP_CB_COMMAND_CONFIG 0x2
|
||||
#define FXP_CB_COMMAND_MCAS 0x3
|
||||
#define FXP_CB_COMMAND_XMIT 0x4
|
||||
#define FXP_CB_COMMAND_RESRV 0x5
|
||||
#define FXP_CB_COMMAND_DUMP 0x6
|
||||
#define FXP_CB_COMMAND_DIAG 0x7
|
||||
/* command flags */
|
||||
#define FXP_CB_COMMAND_SF 0x0008 /* simple/flexible mode */
|
||||
#define FXP_CB_COMMAND_I 0x2000 /* generate interrupt on completion */
|
||||
#define FXP_CB_COMMAND_S 0x4000 /* suspend on completion */
|
||||
#define FXP_CB_COMMAND_EL 0x8000 /* end of list */
|
||||
|
||||
/*
|
||||
* RFA definitions
|
||||
*/
|
||||
|
||||
struct fxp_rfa {
|
||||
volatile u_int16_t rfa_status;
|
||||
volatile u_int16_t rfa_control;
|
||||
volatile u_int8_t link_addr[4];
|
||||
volatile u_int8_t rbd_addr[4];
|
||||
volatile u_int16_t actual_size;
|
||||
volatile u_int16_t size;
|
||||
};
|
||||
#define FXP_RFA_STATUS_RCOL 0x0001 /* receive collision */
|
||||
#define FXP_RFA_STATUS_IAMATCH 0x0002 /* 0 = matches station address */
|
||||
#define FXP_RFA_STATUS_S4 0x0010 /* receive error from PHY */
|
||||
#define FXP_RFA_STATUS_TL 0x0020 /* type/length */
|
||||
#define FXP_RFA_STATUS_FTS 0x0080 /* frame too short */
|
||||
#define FXP_RFA_STATUS_OVERRUN 0x0100 /* DMA overrun */
|
||||
#define FXP_RFA_STATUS_RNR 0x0200 /* no resources */
|
||||
#define FXP_RFA_STATUS_ALIGN 0x0400 /* alignment error */
|
||||
#define FXP_RFA_STATUS_CRC 0x0800 /* CRC error */
|
||||
#define FXP_RFA_STATUS_OK 0x2000 /* packet received okay */
|
||||
#define FXP_RFA_STATUS_C 0x8000 /* packet reception complete */
|
||||
#define FXP_RFA_CONTROL_SF 0x08 /* simple/flexible memory mode */
|
||||
#define FXP_RFA_CONTROL_H 0x10 /* header RFD */
|
||||
#define FXP_RFA_CONTROL_S 0x4000 /* suspend after reception */
|
||||
#define FXP_RFA_CONTROL_EL 0x8000 /* end of list */
|
||||
|
||||
/*
|
||||
* Statistics dump area definitions
|
||||
*/
|
||||
struct fxp_stats {
|
||||
volatile u_int32_t tx_good;
|
||||
volatile u_int32_t tx_maxcols;
|
||||
volatile u_int32_t tx_latecols;
|
||||
volatile u_int32_t tx_underruns;
|
||||
volatile u_int32_t tx_lostcrs;
|
||||
volatile u_int32_t tx_deffered;
|
||||
volatile u_int32_t tx_single_collisions;
|
||||
volatile u_int32_t tx_multiple_collisions;
|
||||
volatile u_int32_t tx_total_collisions;
|
||||
volatile u_int32_t rx_good;
|
||||
volatile u_int32_t rx_crc_errors;
|
||||
volatile u_int32_t rx_alignment_errors;
|
||||
volatile u_int32_t rx_rnr_errors;
|
||||
volatile u_int32_t rx_overrun_errors;
|
||||
volatile u_int32_t rx_cdt_errors;
|
||||
volatile u_int32_t rx_shortframes;
|
||||
volatile u_int32_t completion_status;
|
||||
};
|
||||
#define FXP_STATS_DUMP_COMPLETE 0xa005
|
||||
#define FXP_STATS_DR_COMPLETE 0xa007
|
||||
|
||||
/*
|
||||
* Serial EEPROM control register bits
|
||||
*/
|
||||
#define FXP_EEPROM_EESK 0x01 /* shift clock */
|
||||
#define FXP_EEPROM_EECS 0x02 /* chip select */
|
||||
#define FXP_EEPROM_EEDI 0x04 /* data in */
|
||||
#define FXP_EEPROM_EEDO 0x08 /* data out */
|
||||
|
||||
/*
|
||||
* Serial EEPROM opcodes, including start bit
|
||||
*/
|
||||
#define FXP_EEPROM_OPC_ERASE 0x4
|
||||
#define FXP_EEPROM_OPC_WRITE 0x5
|
||||
#define FXP_EEPROM_OPC_READ 0x6
|
||||
|
||||
/*
|
||||
* Management Data Interface opcodes
|
||||
*/
|
||||
#define FXP_MDI_WRITE 0x1
|
||||
#define FXP_MDI_READ 0x2
|
||||
|
||||
/*
|
||||
* PHY device types
|
||||
*/
|
||||
#define FXP_PHY_DEVICE_MASK 0x3f00
|
||||
#define FXP_PHY_SERIAL_ONLY 0x8000
|
||||
#define FXP_PHY_NONE 0
|
||||
#define FXP_PHY_82553A 1
|
||||
#define FXP_PHY_82553C 2
|
||||
#define FXP_PHY_82503 3
|
||||
#define FXP_PHY_DP83840 4
|
||||
#define FXP_PHY_80C240 5
|
||||
#define FXP_PHY_80C24 6
|
||||
#define FXP_PHY_82555 7
|
||||
#define FXP_PHY_DP83840A 10
|
||||
#define FXP_PHY_82555B 11
|
||||
@@ -1,767 +0,0 @@
|
||||
/*
|
||||
* RTEMS driver for Opencores Ethernet Controller
|
||||
*
|
||||
* Weakly based on dec21140 rtems driver and open_eth linux driver
|
||||
* Written by Jiri Gaisler, Gaisler Research
|
||||
*
|
||||
* 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 driver current only supports architectures with the old style
|
||||
* exception processing. The following checks try to keep this
|
||||
* from being compiled on systems which can't support this driver.
|
||||
*
|
||||
* NOTE: The i386, ARM, and PowerPC use a different interrupt API than
|
||||
* that used by this driver.
|
||||
*/
|
||||
|
||||
#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
|
||||
|
||||
#if defined(__i386__) || defined(__arm__) || defined(__PPC__)
|
||||
#define OPENETH_NOT_SUPPORTED
|
||||
#endif
|
||||
|
||||
#if !defined(OPENETH_NOT_SUPPORTED)
|
||||
#include <bsp.h>
|
||||
#include <rtems.h>
|
||||
|
||||
#include <bsp.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <rtems/error.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
#include <libchip/open_eth.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#ifdef malloc
|
||||
#undef malloc
|
||||
#endif
|
||||
#ifdef free
|
||||
#undef free
|
||||
#endif
|
||||
|
||||
extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
|
||||
|
||||
/*
|
||||
#define OPEN_ETH_DEBUG
|
||||
*/
|
||||
|
||||
#ifdef CPU_U32_FIX
|
||||
extern void ipalign(struct mbuf *m);
|
||||
#endif
|
||||
|
||||
/* message descriptor entry */
|
||||
struct MDTX
|
||||
{
|
||||
char *buf;
|
||||
};
|
||||
|
||||
struct MDRX
|
||||
{
|
||||
struct mbuf *m;
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of OCs supported by this driver
|
||||
*/
|
||||
#define NOCDRIVER 1
|
||||
|
||||
/*
|
||||
* Receive buffer size -- Allow for a full ethernet packet including CRC
|
||||
*/
|
||||
#define RBUF_SIZE 1536
|
||||
|
||||
#define ET_MINLEN 64 /* minimum message length */
|
||||
|
||||
/*
|
||||
* RTEMS event used by interrupt handler to signal driver tasks.
|
||||
* This must not be any of the events used by the network task synchronization.
|
||||
*/
|
||||
#define INTERRUPT_EVENT RTEMS_EVENT_1
|
||||
|
||||
/*
|
||||
* RTEMS event used to start transmit daemon.
|
||||
* This must not be the same as INTERRUPT_EVENT.
|
||||
*/
|
||||
#define START_TRANSMIT_EVENT RTEMS_EVENT_2
|
||||
|
||||
/* event to send when tx buffers become available */
|
||||
#define OPEN_ETH_TX_WAIT_EVENT RTEMS_EVENT_3
|
||||
|
||||
/* suspend when all TX descriptors exhausted */
|
||||
/*
|
||||
#define OETH_SUSPEND_NOTXBUF
|
||||
*/
|
||||
|
||||
#if (MCLBYTES < RBUF_SIZE)
|
||||
# error "Driver must have MCLBYTES > RBUF_SIZE"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Per-device data
|
||||
*/
|
||||
struct open_eth_softc
|
||||
{
|
||||
|
||||
struct arpcom arpcom;
|
||||
|
||||
oeth_regs *regs;
|
||||
|
||||
int acceptBroadcast;
|
||||
rtems_id rxDaemonTid;
|
||||
rtems_id txDaemonTid;
|
||||
|
||||
unsigned int tx_ptr;
|
||||
unsigned int rx_ptr;
|
||||
unsigned int txbufs;
|
||||
unsigned int rxbufs;
|
||||
struct MDTX *txdesc;
|
||||
struct MDRX *rxdesc;
|
||||
rtems_vector_number vector;
|
||||
unsigned int en100MHz;
|
||||
|
||||
/*
|
||||
* Statistics
|
||||
*/
|
||||
unsigned long rxInterrupts;
|
||||
unsigned long rxPackets;
|
||||
unsigned long rxLengthError;
|
||||
unsigned long rxNonOctet;
|
||||
unsigned long rxBadCRC;
|
||||
unsigned long rxOverrun;
|
||||
unsigned long rxMiss;
|
||||
unsigned long rxCollision;
|
||||
|
||||
unsigned long txInterrupts;
|
||||
unsigned long txDeferred;
|
||||
unsigned long txHeartbeat;
|
||||
unsigned long txLateCollision;
|
||||
unsigned long txRetryLimit;
|
||||
unsigned long txUnderrun;
|
||||
unsigned long txLostCarrier;
|
||||
unsigned long txRawWait;
|
||||
};
|
||||
|
||||
static struct open_eth_softc oc;
|
||||
|
||||
/* OPEN_ETH interrupt handler */
|
||||
|
||||
static rtems_isr
|
||||
open_eth_interrupt_handler (rtems_vector_number v)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
/* read and clear interrupt cause */
|
||||
|
||||
status = oc.regs->int_src;
|
||||
oc.regs->int_src = status;
|
||||
|
||||
/* Frame received? */
|
||||
|
||||
if (status & (OETH_INT_RXF | OETH_INT_RXE))
|
||||
{
|
||||
oc.rxInterrupts++;
|
||||
rtems_bsdnet_event_send (oc.rxDaemonTid, INTERRUPT_EVENT);
|
||||
}
|
||||
#ifdef OETH_SUSPEND_NOTXBUF
|
||||
if (status & (OETH_INT_MASK_TXB | OETH_INT_MASK_TXC | OETH_INT_MASK_TXE))
|
||||
{
|
||||
oc.txInterrupts++;
|
||||
rtems_bsdnet_event_send (oc.txDaemonTid, OPEN_ETH_TX_WAIT_EVENT);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
#ifdef __leon__
|
||||
LEON_Clear_interrupt(v-0x10);
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
static uint32_t read_mii(uint32_t addr)
|
||||
{
|
||||
while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {}
|
||||
oc.regs->miiaddress = addr << 8;
|
||||
oc.regs->miicommand = OETH_MIICOMMAND_RSTAT;
|
||||
while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {}
|
||||
if (!(oc.regs->miistatus & OETH_MIISTATUS_NVALID))
|
||||
return(oc.regs->miirx_data);
|
||||
else {
|
||||
printf("open_eth: failed to read mii\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_mii(uint32_t addr, uint32_t data)
|
||||
{
|
||||
while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {}
|
||||
oc.regs->miiaddress = addr << 8;
|
||||
oc.regs->miitx_data = data;
|
||||
oc.regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
|
||||
while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {}
|
||||
}
|
||||
/*
|
||||
* Initialize the ethernet hardware
|
||||
*/
|
||||
static void
|
||||
open_eth_initialize_hardware (struct open_eth_softc *sc)
|
||||
{
|
||||
struct mbuf *m;
|
||||
int i;
|
||||
int mii_cr = 0;
|
||||
|
||||
oeth_regs *regs;
|
||||
|
||||
regs = sc->regs;
|
||||
|
||||
/* Reset the controller. */
|
||||
|
||||
regs->ctrlmoder = 0;
|
||||
regs->moder = OETH_MODER_RST; /* Reset ON */
|
||||
regs->moder = 0; /* Reset OFF */
|
||||
|
||||
/* reset PHY and wait for complettion */
|
||||
mii_cr = 0x3300;
|
||||
if (!sc->en100MHz) mii_cr = 0;
|
||||
write_mii(0, mii_cr | 0x8000);
|
||||
while (read_mii(0) & 0x8000) {}
|
||||
if (!sc->en100MHz) write_mii(0, 0);
|
||||
mii_cr = read_mii(0);
|
||||
printf("open_eth: driver attached, PHY config : 0x%04" PRIx32 "\n", read_mii(0));
|
||||
|
||||
#ifdef OPEN_ETH_DEBUG
|
||||
printf("mii_cr: %04x\n", mii_cr);
|
||||
for (i=0;i<21;i++)
|
||||
printf("mii_reg %2d : 0x%04x\n", i, read_mii(i));
|
||||
#endif
|
||||
|
||||
/* Setting TXBD base to sc->txbufs */
|
||||
|
||||
regs->tx_bd_num = sc->txbufs;
|
||||
|
||||
/* Initialize rx/tx pointers. */
|
||||
|
||||
sc->rx_ptr = 0;
|
||||
sc->tx_ptr = 0;
|
||||
|
||||
/* Set min/max packet length */
|
||||
regs->packet_len = 0x00400600;
|
||||
|
||||
/* Set IPGT register to recomended value */
|
||||
regs->ipgt = 0x00000015;
|
||||
|
||||
/* Set IPGR1 register to recomended value */
|
||||
regs->ipgr1 = 0x0000000c;
|
||||
|
||||
/* Set IPGR2 register to recomended value */
|
||||
regs->ipgr2 = 0x00000012;
|
||||
|
||||
/* Set COLLCONF register to recomended value */
|
||||
regs->collconf = 0x000f003f;
|
||||
|
||||
/* initialize TX descriptors */
|
||||
|
||||
sc->txdesc = calloc(sc->txbufs, sizeof(*sc->txdesc));
|
||||
for (i = 0; i < sc->txbufs; i++)
|
||||
{
|
||||
sc->regs->xd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC;
|
||||
sc->txdesc[i].buf = calloc(1, OETH_MAXBUF_LEN);
|
||||
#ifdef OPEN_ETH_DEBUG
|
||||
printf("TXBUF: %08x\n", (int) sc->txdesc[i].buf);
|
||||
#endif
|
||||
}
|
||||
sc->regs->xd[sc->txbufs - 1].len_status |= OETH_TX_BD_WRAP;
|
||||
|
||||
/* allocate RX buffers */
|
||||
|
||||
sc->rxdesc = calloc(sc->rxbufs, sizeof(*sc->rxdesc));
|
||||
for (i = 0; i < sc->rxbufs; i++)
|
||||
{
|
||||
|
||||
MGETHDR (m, M_WAIT, MT_DATA);
|
||||
MCLGET (m, M_WAIT);
|
||||
m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
|
||||
sc->rxdesc[i].m = m;
|
||||
sc->regs->xd[i + sc->txbufs].addr = mtod (m, uint32_t*);
|
||||
sc->regs->xd[i + sc->txbufs].len_status =
|
||||
OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
|
||||
#ifdef OPEN_ETH_DEBUG
|
||||
printf("RXBUF: %08x\n", (int) sc->rxdesc[i].m);
|
||||
#endif
|
||||
}
|
||||
sc->regs->xd[sc->rxbufs + sc->txbufs - 1].len_status |= OETH_RX_BD_WRAP;
|
||||
|
||||
|
||||
/* set ethernet address. */
|
||||
|
||||
regs->mac_addr1 = sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
|
||||
|
||||
uint32_t mac_addr0;
|
||||
mac_addr0 = sc->arpcom.ac_enaddr[2];
|
||||
mac_addr0 <<= 8;
|
||||
mac_addr0 |= sc->arpcom.ac_enaddr[3];
|
||||
mac_addr0 <<= 8;
|
||||
mac_addr0 |= sc->arpcom.ac_enaddr[4];
|
||||
mac_addr0 <<= 8;
|
||||
mac_addr0 |= sc->arpcom.ac_enaddr[5];
|
||||
|
||||
regs->mac_addr0 = mac_addr0;
|
||||
|
||||
/* install interrupt vector */
|
||||
set_vector (open_eth_interrupt_handler, sc->vector, 1);
|
||||
|
||||
/* clear all pending interrupts */
|
||||
|
||||
regs->int_src = 0xffffffff;
|
||||
|
||||
/* MAC mode register: PAD, IFG, CRCEN */
|
||||
|
||||
regs->moder = OETH_MODER_PAD | OETH_MODER_CRCEN | ((mii_cr & 0x100) << 2);
|
||||
|
||||
/* enable interrupts */
|
||||
|
||||
regs->int_mask = OETH_INT_MASK_RXF | OETH_INT_MASK_RXE | OETH_INT_MASK_RXC;
|
||||
|
||||
#ifdef OETH_SUSPEND_NOTXBUF
|
||||
regs->int_mask |= OETH_INT_MASK_TXB | OETH_INT_MASK_TXC | OETH_INT_MASK_TXE | OETH_INT_BUSY;*/
|
||||
sc->regs->xd[(sc->txbufs - 1)/2].len_status |= OETH_TX_BD_IRQ;
|
||||
sc->regs->xd[sc->txbufs - 1].len_status |= OETH_TX_BD_IRQ;
|
||||
#endif
|
||||
|
||||
regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
|
||||
}
|
||||
|
||||
static void
|
||||
open_eth_rxDaemon (void *arg)
|
||||
{
|
||||
struct ether_header *eh;
|
||||
struct open_eth_softc *dp = (struct open_eth_softc *) &oc;
|
||||
struct ifnet *ifp = &dp->arpcom.ac_if;
|
||||
struct mbuf *m;
|
||||
unsigned int len;
|
||||
uint32_t len_status;
|
||||
unsigned int bad;
|
||||
rtems_event_set events;
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
||||
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
||||
RTEMS_NO_TIMEOUT, &events);
|
||||
#ifdef OPEN_ETH_DEBUG
|
||||
printf ("r\n");
|
||||
#endif
|
||||
|
||||
while (!
|
||||
((len_status =
|
||||
dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status) & OETH_RX_BD_EMPTY))
|
||||
{
|
||||
bad = 0;
|
||||
if (len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT))
|
||||
{
|
||||
dp->rxLengthError++;
|
||||
bad = 1;
|
||||
}
|
||||
if (len_status & OETH_RX_BD_DRIBBLE)
|
||||
{
|
||||
dp->rxNonOctet++;
|
||||
bad = 1;
|
||||
}
|
||||
if (len_status & OETH_RX_BD_CRCERR)
|
||||
{
|
||||
dp->rxBadCRC++;
|
||||
bad = 1;
|
||||
}
|
||||
if (len_status & OETH_RX_BD_OVERRUN)
|
||||
{
|
||||
dp->rxOverrun++;
|
||||
bad = 1;
|
||||
}
|
||||
if (len_status & OETH_RX_BD_MISS)
|
||||
{
|
||||
dp->rxMiss++;
|
||||
bad = 1;
|
||||
}
|
||||
if (len_status & OETH_RX_BD_LATECOL)
|
||||
{
|
||||
dp->rxCollision++;
|
||||
bad = 1;
|
||||
}
|
||||
|
||||
if (!bad)
|
||||
{
|
||||
/* pass on the packet in the receive buffer */
|
||||
len = len_status >> 16;
|
||||
m = (struct mbuf *) (dp->rxdesc[dp->rx_ptr].m);
|
||||
m->m_len = m->m_pkthdr.len =
|
||||
len - sizeof (struct ether_header);
|
||||
eh = mtod (m, struct ether_header *);
|
||||
m->m_data += sizeof (struct ether_header);
|
||||
#ifdef CPU_U32_FIX
|
||||
ipalign(m); /* Align packet on 32-bit boundary */
|
||||
#endif
|
||||
|
||||
ether_input (ifp, eh, m);
|
||||
|
||||
/* get a new mbuf */
|
||||
MGETHDR (m, M_WAIT, MT_DATA);
|
||||
MCLGET (m, M_WAIT);
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
dp->rxdesc[dp->rx_ptr].m = m;
|
||||
dp->regs->xd[dp->rx_ptr + dp->txbufs].addr =
|
||||
(uint32_t*) mtod (m, void *);
|
||||
dp->rxPackets++;
|
||||
}
|
||||
|
||||
dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status =
|
||||
(dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status &
|
||||
~OETH_TX_BD_STATS) | OETH_TX_BD_READY;
|
||||
dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int inside = 0;
|
||||
static void
|
||||
sendpacket (struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct open_eth_softc *dp = ifp->if_softc;
|
||||
unsigned char *temp;
|
||||
struct mbuf *n;
|
||||
uint32_t len, len_status;
|
||||
|
||||
if (inside) printf ("error: sendpacket re-entered!!\n");
|
||||
inside = 1;
|
||||
/*
|
||||
* Waiting for Transmitter ready
|
||||
*/
|
||||
n = m;
|
||||
|
||||
while (dp->regs->xd[dp->tx_ptr].len_status & OETH_TX_BD_READY)
|
||||
{
|
||||
#ifdef OETH_SUSPEND_NOTXBUF
|
||||
rtems_event_set events;
|
||||
rtems_bsdnet_event_receive (OPEN_ETH_TX_WAIT_EVENT,
|
||||
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
||||
RTEMS_MILLISECONDS_TO_TICKS(500), &events);
|
||||
#endif
|
||||
}
|
||||
|
||||
len = 0;
|
||||
temp = (unsigned char *) dp->txdesc[dp->tx_ptr].buf;
|
||||
dp->regs->xd[dp->tx_ptr].addr = (uint32_t*) temp;
|
||||
|
||||
#ifdef OPEN_ETH_DEBUG
|
||||
printf("TXD: 0x%08x\n", (int) m->m_data);
|
||||
#endif
|
||||
for (;;)
|
||||
{
|
||||
#ifdef OPEN_ETH_DEBUG
|
||||
int i;
|
||||
printf("MBUF: 0x%08x : ", (int) m->m_data);
|
||||
for (i=0;i<m->m_len;i++)
|
||||
printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
|
||||
printf("\n");
|
||||
#endif
|
||||
len += m->m_len;
|
||||
if (len <= RBUF_SIZE)
|
||||
memcpy ((void *) temp, (char *) m->m_data, m->m_len);
|
||||
temp += m->m_len;
|
||||
if ((m = m->m_next) == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
m_freem (n);
|
||||
|
||||
/* don't send long packets */
|
||||
|
||||
if (len <= RBUF_SIZE) {
|
||||
|
||||
/* Clear all of the status flags. */
|
||||
len_status = dp->regs->xd[dp->tx_ptr].len_status & ~OETH_TX_BD_STATS;
|
||||
|
||||
/* If the frame is short, tell CPM to pad it. */
|
||||
if (len < ET_MINLEN) {
|
||||
len_status |= OETH_TX_BD_PAD;
|
||||
len = ET_MINLEN;
|
||||
}
|
||||
else
|
||||
len_status &= ~OETH_TX_BD_PAD;
|
||||
|
||||
/* write buffer descriptor length and status */
|
||||
len_status &= 0x0000ffff;
|
||||
len_status |= (len << 16) | (OETH_TX_BD_READY | OETH_TX_BD_CRC);
|
||||
dp->regs->xd[dp->tx_ptr].len_status = len_status;
|
||||
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
|
||||
|
||||
}
|
||||
inside = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver transmit daemon
|
||||
*/
|
||||
static void
|
||||
open_eth_txDaemon (void *arg)
|
||||
{
|
||||
struct open_eth_softc *sc = (struct open_eth_softc *) arg;
|
||||
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||
struct mbuf *m;
|
||||
rtems_event_set events;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
* Wait for packet
|
||||
*/
|
||||
|
||||
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
|
||||
RTEMS_EVENT_ANY | RTEMS_WAIT,
|
||||
RTEMS_NO_TIMEOUT, &events);
|
||||
#ifdef OPEN_ETH_DEBUG
|
||||
printf ("t\n");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Send packets till queue is empty
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
* Get the next mbuf chain to transmit.
|
||||
*/
|
||||
IF_DEQUEUE (&ifp->if_snd, m);
|
||||
if (!m)
|
||||
break;
|
||||
sendpacket (ifp, m);
|
||||
}
|
||||
ifp->if_flags &= ~IFF_OACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
open_eth_start (struct ifnet *ifp)
|
||||
{
|
||||
struct open_eth_softc *sc = ifp->if_softc;
|
||||
|
||||
rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
|
||||
ifp->if_flags |= IFF_OACTIVE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize and start the device
|
||||
*/
|
||||
static void
|
||||
open_eth_init (void *arg)
|
||||
{
|
||||
struct open_eth_softc *sc = arg;
|
||||
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||
|
||||
if (sc->txDaemonTid == 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Set up OPEN_ETH hardware
|
||||
*/
|
||||
open_eth_initialize_hardware (sc);
|
||||
|
||||
/*
|
||||
* Start driver tasks
|
||||
*/
|
||||
sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
|
||||
open_eth_rxDaemon, sc);
|
||||
sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
|
||||
open_eth_txDaemon, sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the world that we're running.
|
||||
*/
|
||||
ifp->if_flags |= IFF_RUNNING;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop the device
|
||||
*/
|
||||
static void
|
||||
open_eth_stop (struct open_eth_softc *sc)
|
||||
{
|
||||
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||
|
||||
ifp->if_flags &= ~IFF_RUNNING;
|
||||
|
||||
sc->regs->moder = 0; /* RX/TX OFF */
|
||||
sc->regs->moder = OETH_MODER_RST; /* Reset ON */
|
||||
sc->regs->moder = 0; /* Reset OFF */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Show interface statistics
|
||||
*/
|
||||
static void
|
||||
open_eth_stats (struct open_eth_softc *sc)
|
||||
{
|
||||
printf (" Rx Packets:%-8lu", sc->rxPackets);
|
||||
printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
|
||||
printf (" Length:%-8lu", sc->rxLengthError);
|
||||
printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
|
||||
printf (" Bad CRC:%-8lu", sc->rxBadCRC);
|
||||
printf (" Overrun:%-8lu", sc->rxOverrun);
|
||||
printf (" Miss:%-8lu", sc->rxMiss);
|
||||
printf (" Collision:%-8lu\n", sc->rxCollision);
|
||||
|
||||
printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
|
||||
printf (" Deferred:%-8lu", sc->txDeferred);
|
||||
printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
|
||||
printf (" No Carrier:%-8lu", sc->txLostCarrier);
|
||||
printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
|
||||
printf (" Late Collision:%-8lu\n", sc->txLateCollision);
|
||||
printf (" Underrun:%-8lu", sc->txUnderrun);
|
||||
printf (" Raw output wait:%-8lu\n", sc->txRawWait);
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver ioctl handler
|
||||
*/
|
||||
static int
|
||||
open_eth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
|
||||
{
|
||||
struct open_eth_softc *sc = ifp->if_softc;
|
||||
int error = 0;
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case SIOCGIFADDR:
|
||||
case SIOCSIFADDR:
|
||||
ether_ioctl (ifp, command, data);
|
||||
break;
|
||||
|
||||
case SIOCSIFFLAGS:
|
||||
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
|
||||
{
|
||||
case IFF_RUNNING:
|
||||
open_eth_stop (sc);
|
||||
break;
|
||||
|
||||
case IFF_UP:
|
||||
open_eth_init (sc);
|
||||
break;
|
||||
|
||||
case IFF_UP | IFF_RUNNING:
|
||||
open_eth_stop (sc);
|
||||
open_eth_init (sc);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SIO_RTEMS_SHOW_STATS:
|
||||
open_eth_stats (sc);
|
||||
break;
|
||||
|
||||
/*
|
||||
* FIXME: All sorts of multicast commands need to be added here!
|
||||
*/
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach an OPEN_ETH driver to the system
|
||||
*/
|
||||
int
|
||||
rtems_open_eth_driver_attach (struct rtems_bsdnet_ifconfig *config,
|
||||
open_eth_configuration_t * chip)
|
||||
{
|
||||
struct open_eth_softc *sc;
|
||||
struct ifnet *ifp;
|
||||
int mtu;
|
||||
int unitNumber;
|
||||
char *unitName;
|
||||
|
||||
/* parse driver name */
|
||||
if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
|
||||
return 0;
|
||||
|
||||
sc = &oc;
|
||||
ifp = &sc->arpcom.ac_if;
|
||||
memset (sc, 0, sizeof (*sc));
|
||||
|
||||
if (config->hardware_address)
|
||||
{
|
||||
memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
|
||||
ETHER_ADDR_LEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
|
||||
}
|
||||
|
||||
if (config->mtu)
|
||||
mtu = config->mtu;
|
||||
else
|
||||
mtu = ETHERMTU;
|
||||
|
||||
sc->acceptBroadcast = !config->ignore_broadcast;
|
||||
sc->regs = chip->base_address;
|
||||
sc->vector = chip->vector;
|
||||
sc->txbufs = chip->txd_count;
|
||||
sc->rxbufs = chip->rxd_count;
|
||||
sc->en100MHz = chip->en100MHz;
|
||||
|
||||
|
||||
/*
|
||||
* Set up network interface values
|
||||
*/
|
||||
ifp->if_softc = sc;
|
||||
ifp->if_unit = unitNumber;
|
||||
ifp->if_name = unitName;
|
||||
ifp->if_mtu = mtu;
|
||||
ifp->if_init = open_eth_init;
|
||||
ifp->if_ioctl = open_eth_ioctl;
|
||||
ifp->if_start = open_eth_start;
|
||||
ifp->if_output = ether_output;
|
||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
|
||||
if (ifp->if_snd.ifq_maxlen == 0)
|
||||
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
||||
|
||||
/*
|
||||
* Attach the interface
|
||||
*/
|
||||
if_attach (ifp);
|
||||
ether_ifattach (ifp);
|
||||
|
||||
#ifdef OPEN_ETH_DEBUG
|
||||
printf ("OPEN_ETH : driver has been attached\n");
|
||||
#endif
|
||||
return 1;
|
||||
};
|
||||
|
||||
#endif /* OPENETH_NOT_SUPPORTED */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,118 +0,0 @@
|
||||
#ifndef _SMC91111_CONFIG_H_
|
||||
#define _SMC91111_CONFIG_H_
|
||||
|
||||
/*
|
||||
* RTEMS event used by interrupt handler to signal driver tasks.
|
||||
* This must not be any of the events used by the network task synchronization.
|
||||
*/
|
||||
#define INTERRUPT_EVENT RTEMS_EVENT_1
|
||||
|
||||
/*
|
||||
* RTEMS event used to start transmit daemon.
|
||||
* This must not be the same as INTERRUPT_EVENT.
|
||||
*/
|
||||
#define START_TRANSMIT_EVENT RTEMS_EVENT_2
|
||||
|
||||
/* event to send when tx buffers become available */
|
||||
#define SMC91111_TX_WAIT_EVENT RTEMS_EVENT_3
|
||||
|
||||
|
||||
/* Number of OCs supported by this driver*/
|
||||
#define NOCDRIVER 1
|
||||
|
||||
/* Receive buffer size -- Allow for a full ethernet packet including CRC */
|
||||
#define RBUF_SIZE 1536
|
||||
|
||||
#define ET_MINLEN 64 /* minimum message length */
|
||||
|
||||
#if (MCLBYTES < RBUF_SIZE)
|
||||
# error "Driver must have MCLBYTES > RBUF_SIZE"
|
||||
#endif
|
||||
|
||||
/* ----------------- cygdriver params ----------------- */
|
||||
|
||||
#define LAN91CXX_32BIT_RX
|
||||
#define LAN91CXX_IS_LAN91C111
|
||||
|
||||
/* ----------------- compat layer ----------------- */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint32_t CYG_WORD;
|
||||
typedef uint8_t CYG_BYTE;
|
||||
typedef uint16_t CYG_WORD16;
|
||||
typedef uint32_t CYG_WORD32;
|
||||
|
||||
#ifndef CYG_SWAP16
|
||||
# define CYG_SWAP16(_x_) \
|
||||
({ uint16_t _x = (_x_); ((_x << 8) | (_x >> 8)); })
|
||||
#endif
|
||||
|
||||
#ifndef CYG_SWAP32
|
||||
# define CYG_SWAP32(_x_) \
|
||||
({ uint32_t _x = (_x_); \
|
||||
((_x << 24) | \
|
||||
((0x0000FF00UL & _x) << 8) | \
|
||||
((0x00FF0000UL & _x) >> 8) | \
|
||||
(_x >> 24)); })
|
||||
#endif
|
||||
|
||||
# define CYG_CPU_TO_BE16(_x_) (_x_)
|
||||
# define CYG_CPU_TO_BE32(_x_) (_x_)
|
||||
# define CYG_BE16_TO_CPU(_x_) (_x_)
|
||||
# define CYG_BE32_TO_CPU(_x_) (_x_)
|
||||
|
||||
# define CYG_CPU_TO_LE16(_x_) CYG_SWAP16((_x_))
|
||||
# define CYG_CPU_TO_LE32(_x_) CYG_SWAP32((_x_))
|
||||
# define CYG_LE16_TO_CPU(_x_) CYG_SWAP16((_x_))
|
||||
# define CYG_LE32_TO_CPU(_x_) CYG_SWAP32((_x_))
|
||||
|
||||
#define CYG_MACRO_START do {
|
||||
#define CYG_MACRO_END } while (0)
|
||||
#define HAL_IO_BARRIER() \
|
||||
__asm__ volatile ( "" : : : "memory" )
|
||||
|
||||
#define HAL_READ_UINT8( _register_, _value_ ) \
|
||||
CYG_MACRO_START \
|
||||
((_value_) = *((volatile CYG_BYTE *)(_register_))); \
|
||||
HAL_IO_BARRIER (); \
|
||||
CYG_MACRO_END
|
||||
|
||||
#define HAL_WRITE_UINT8( _register_, _value_ ) \
|
||||
CYG_MACRO_START \
|
||||
(*((volatile CYG_BYTE *)(_register_)) = (_value_)); \
|
||||
HAL_IO_BARRIER (); \
|
||||
CYG_MACRO_END
|
||||
|
||||
#define HAL_READ_UINT16( _register_, _value_ ) \
|
||||
CYG_MACRO_START \
|
||||
((_value_) = *((volatile CYG_WORD16 *)(_register_))); \
|
||||
HAL_IO_BARRIER (); \
|
||||
CYG_MACRO_END
|
||||
|
||||
#define HAL_WRITE_UINT16( _register_, _value_ ) \
|
||||
CYG_MACRO_START \
|
||||
(*((volatile CYG_WORD16 *)(_register_)) = (_value_)); \
|
||||
HAL_IO_BARRIER (); \
|
||||
CYG_MACRO_END
|
||||
|
||||
#define HAL_READ_UINT32( _register_, _value_ ) \
|
||||
CYG_MACRO_START \
|
||||
((_value_) = *((volatile CYG_WORD32 *)(_register_))); \
|
||||
HAL_IO_BARRIER (); \
|
||||
CYG_MACRO_END
|
||||
|
||||
#define HAL_READ_UINT16( _register_, _value_ ) \
|
||||
CYG_MACRO_START \
|
||||
((_value_) = *((volatile CYG_WORD16 *)(_register_))); \
|
||||
HAL_IO_BARRIER (); \
|
||||
CYG_MACRO_END
|
||||
|
||||
#define CYG_ASSERT(c,p) do { if (!(c)) { while(1) { printf(p);} }; } while(0)
|
||||
|
||||
#define HAL_DELAY_US(p) rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (p))
|
||||
|
||||
|
||||
#endif /* _SMC_91111_CONFIG_H_ */
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
The Mostek M48T08 is compatible with the Dallas Semiconductor DS1643. Please
|
||||
use that driver.
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
|
||||
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.
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
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 +0,0 @@
|
||||
This is supported by the m48t08 driver.
|
||||
@@ -1 +0,0 @@
|
||||
This is supported by the mc146818a driver.
|
||||
@@ -1,33 +0,0 @@
|
||||
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.
|
||||
|
||||
@@ -1,461 +0,0 @@
|
||||
/* 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,
|
||||
};
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
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.
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
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.
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
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.
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
The Exar XR88681 is an enhanced version of the Motorola MC68681 and is
|
||||
supported by the mc68681 driver.
|
||||
@@ -1,74 +0,0 @@
|
||||
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.
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
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.
|
||||
|
||||
@@ -1,776 +0,0 @@
|
||||
/*
|
||||
* 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)
|
||||
);
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
||||
},
|
||||
};
|
||||
@@ -1,323 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* 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_ */
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
@@ -1,814 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
};
|
||||
@@ -1,875 +0,0 @@
|
||||
/**
|
||||
* @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 );
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,893 +0,0 @@
|
||||
/*
|
||||
* 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 );
|
||||
}
|
||||
@@ -1,420 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -13,17 +13,7 @@ TMPINSTALL_FILES = $(PROJECT_LIB)/librtemsbsp.a
|
||||
|
||||
CLEANFILES = o-optimize/librtemsbsp.a
|
||||
|
||||
SRCS += ../lib/libbsp/@RTEMS_CPU@/@RTEMS_BSP_FAMILY@/libbsp.a
|
||||
|
||||
SRCS += ../libchip/libflash.a
|
||||
SRCS += ../libchip/librtcio.a
|
||||
SRCS += ../libchip/libserialio.a
|
||||
SRCS += ../libchip/libide.a
|
||||
if HAS_NETWORKING
|
||||
SRCS += ../libchip/libnetchip.a
|
||||
endif
|
||||
SRCS += ../libchip/libi2cio.a
|
||||
SRCS += ../libchip/libdisplay.a
|
||||
SRCS = ../lib/libbsp/@RTEMS_CPU@/@RTEMS_BSP_FAMILY@/libbsp.a
|
||||
|
||||
if HAS_MP
|
||||
SRCS += ../libchip/libshmdr.a
|
||||
|
||||
Reference in New Issue
Block a user