summaryrefslogtreecommitdiff
path: root/components/drivers
diff options
context:
space:
mode:
authorArda <[email protected]>2014-11-24 11:57:31 +0800
committerArda <[email protected]>2014-11-24 11:57:31 +0800
commit143d3b82244b977735649e7d7c201d2affe67460 (patch)
tree61503d3a150cef8d8184c858efc139b146b50cf6 /components/drivers
parentbc2a890ab08d163ccea323f7e719c4fdf53050cd (diff)
parent9ecd18411fc1344e3d080d844b60c7070c3fb4d8 (diff)
Merge pull request #2 from RT-Thread/master
update from official source
Diffstat (limited to 'components/drivers')
-rw-r--r--components/drivers/i2c/i2c-bit-ops.c3
-rw-r--r--components/drivers/i2c/i2c_core.c11
-rw-r--r--components/drivers/i2c/i2c_dev.c11
-rw-r--r--components/drivers/sensors/SConscript12
-rw-r--r--components/drivers/sensors/sensor.cpp135
-rw-r--r--components/drivers/sensors/sensor.h1011
-rw-r--r--components/drivers/serial/serial.c728
-rw-r--r--components/drivers/spi/SConscript26
-rw-r--r--components/drivers/spi/device_driver_list.txt15
-rw-r--r--components/drivers/spi/enc28j60.c876
-rw-r--r--components/drivers/spi/enc28j60.h329
-rw-r--r--components/drivers/spi/spi_dev.c35
-rw-r--r--components/drivers/spi/spi_flash_at45dbxx.c437
-rw-r--r--components/drivers/spi/spi_flash_at45dbxx.h17
-rw-r--r--components/drivers/spi/spi_flash_sst25vfxx.c346
-rw-r--r--components/drivers/spi/spi_flash_sst25vfxx.h32
-rw-r--r--components/drivers/spi/spi_flash_w25qxx.c371
-rw-r--r--components/drivers/spi/spi_flash_w25qxx.h34
-rw-r--r--components/drivers/spi/spi_wifi_rw009.c847
-rw-r--r--components/drivers/spi/spi_wifi_rw009.h226
-rw-r--r--components/drivers/src/workqueue.c2
21 files changed, 5084 insertions, 420 deletions
diff --git a/components/drivers/i2c/i2c-bit-ops.c b/components/drivers/i2c/i2c-bit-ops.c
index 0d82d55fd4..d4a26ea72a 100644
--- a/components/drivers/i2c/i2c-bit-ops.c
+++ b/components/drivers/i2c/i2c-bit-ops.c
@@ -451,9 +451,6 @@ static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
const char *bus_name)
{
- struct rt_i2c_bit_ops *bit_ops = bus->priv;
- RT_ASSERT(bit_ops != RT_NULL);
-
bus->ops = &i2c_bit_bus_ops;
return rt_i2c_bus_device_register(bus, bus_name);
diff --git a/components/drivers/i2c/i2c_core.c b/components/drivers/i2c/i2c_core.c
index f274f70fcd..09616235d1 100644
--- a/components/drivers/i2c/i2c_core.c
+++ b/components/drivers/i2c/i2c_core.c
@@ -24,8 +24,6 @@
#include <rtdevice.h>
-static struct rt_mutex i2c_core_lock;
-
rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus,
const char *bus_name)
{
@@ -33,17 +31,12 @@ rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus,
rt_mutex_init(&bus->lock, "i2c_bus_lock", RT_IPC_FLAG_FIFO);
- rt_mutex_take(&i2c_core_lock, RT_WAITING_FOREVER);
-
- if (bus->timeout == 0)
- bus->timeout = RT_TICK_PER_SECOND;
+ if (bus->timeout == 0) bus->timeout = RT_TICK_PER_SECOND;
res = rt_i2c_bus_device_device_init(bus, bus_name);
i2c_dbg("I2C bus [%s] registered\n", bus_name);
- rt_mutex_release(&i2c_core_lock);
-
return res;
}
@@ -136,6 +129,6 @@ rt_size_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
int rt_i2c_core_init(void)
{
- return rt_mutex_init(&i2c_core_lock, "i2c_core_lock", RT_IPC_FLAG_FIFO);
+ return 0;
}
INIT_COMPONENT_EXPORT(rt_i2c_core_init);
diff --git a/components/drivers/i2c/i2c_dev.c b/components/drivers/i2c/i2c_dev.c
index cce53d5c92..4b811c62ea 100644
--- a/components/drivers/i2c/i2c_dev.c
+++ b/components/drivers/i2c/i2c_dev.c
@@ -20,18 +20,11 @@
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
+ * 2014-08-03 bernard fix some compiling warning
*/
#include <rtdevice.h>
-static rt_err_t i2c_bus_device_init(rt_device_t dev)
-{
- struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
- RT_ASSERT(bus != RT_NULL);
-
- return RT_EOK;
-}
-
static rt_size_t i2c_bus_device_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
@@ -122,7 +115,7 @@ rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
/* set device type */
device->type = RT_Device_Class_I2CBUS;
/* initialize device interface */
- device->init = i2c_bus_device_init;
+ device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = i2c_bus_device_read;
diff --git a/components/drivers/sensors/SConscript b/components/drivers/sensors/SConscript
new file mode 100644
index 0000000000..14a7cd2450
--- /dev/null
+++ b/components/drivers/sensors/SConscript
@@ -0,0 +1,12 @@
+# SConscript for sensor framework
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c') + Glob('*.cpp')
+CPPPATH = [cwd, cwd + '/../include']
+
+group = DefineGroup('Sensors', src, depend = ['RT_USING_SENSOR', 'RT_USING_DEVICE'], CPPPATH = CPPPATH)
+
+Return('group')
+
diff --git a/components/drivers/sensors/sensor.cpp b/components/drivers/sensors/sensor.cpp
new file mode 100644
index 0000000000..52718183f3
--- /dev/null
+++ b/components/drivers/sensors/sensor.cpp
@@ -0,0 +1,135 @@
+#include <stddef.h>
+#include "sensor.h"
+
+/**
+ * Sensor
+ */
+Sensor::Sensor()
+{
+ this->next = this->prev = NULL;
+ Subscribe(NULL, NULL);
+}
+
+Sensor::~Sensor()
+{
+}
+
+int Sensor::GetType(void)
+{
+ return this->type;
+}
+
+int Sensor::Subscribe(SensorEventHandler_t *handler, void *user_data)
+{
+ this->evtHandler = handler;
+ this->userData = user_data;
+
+ return 0;
+}
+
+int Sensor::Publish(sensors_event_t *event)
+{
+ if (this->evtHandler != NULL)
+ {
+ /* invoke subscribed handler */
+ (*evtHandler)(this, event, this->userData);
+ }
+
+ return 0;
+}
+
+/**
+ * Sensor Manager
+ */
+/* sensor manager instance */
+static SensorManager _sensor_manager;
+
+SensorManager::SensorManager()
+{
+ sensorList = NULL;
+}
+
+SensorManager::~SensorManager()
+{
+}
+
+int SensorManager::RegisterSensor(Sensor *sensor)
+{
+ SensorManager *self = &_sensor_manager;
+
+ RT_ASSERT(sensor != RT_NULL);
+
+ /* add sensor into the list */
+ if (self->sensorList = NULL)
+ {
+ sensor->prev = sensor->next = sensor;
+ }
+ else
+ {
+ sensor->prev = self->sensorList;
+ sensor->next = self->sensorList->next;
+
+ self->sensorList->next->prev = sensor;
+ self->sensorList->next = sensor;
+ }
+
+ /* point the sensorList to this sensor */
+ self->sensorList = sensor;
+
+ return 0;
+}
+
+int SensorManager::DeregisterSensor(Sensor *sensor)
+{
+ SensorManager *self = &_sensor_manager;
+
+ /* disconnect sensor list */
+ sensor->next->prev = sensor->prev;
+ sensor->prev->next = sensor->next;
+
+ /* check the sensorList */
+ if (sensor == self->sensorList)
+ {
+ if (sensor->next == sensor) self->sensorList = NULL; /* empty list */
+ else self->sensorList = sensor->next;
+ }
+
+ /* re-initialize sensor node */
+ sensor->next = sensor->prev = sensor;
+
+ return 0;
+}
+
+Sensor *SensorManager::GetDefaultSensor(int type)
+{
+ SensorManager *self = &_sensor_manager;
+ Sensor *sensor = self->sensorList;
+
+ if (sensor == NULL) return NULL;
+
+ do
+ {
+ /* find the same type */
+ if (sensor->GetType() == type) return sensor;
+
+ sensor = sensor->next;
+ }
+ while (sensor != self->sensorList);
+
+ return NULL;
+}
+
+int SensorManager::Subscribe(int type, SensorEventHandler_t *handler, void *user_data)
+{
+ Sensor *sensor;
+
+ sensor = SensorManager::GetDefaultSensor(type);
+ if (sensor != NULL)
+ {
+ sensor->Subscribe(handler, user_data);
+ return 0;
+ }
+
+ return -1;
+}
+
diff --git a/components/drivers/sensors/sensor.h b/components/drivers/sensors/sensor.h
new file mode 100644
index 0000000000..09929d1b58
--- /dev/null
+++ b/components/drivers/sensors/sensor.h
@@ -0,0 +1,1011 @@
+/*
+ * File : sensors.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2014, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2014-08-03 Bernard the first version
+ */
+
+/* Modified from: https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */
+
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SENSORS_H__
+#define SENSORS_H__
+
+#include <rtdevice.h>
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/**
+ * Handles must be higher than SENSORS_HANDLE_BASE and must be unique.
+ * A Handle identifies a given sensors. The handle is used to activate
+ * and/or deactivate sensors.
+ * In this version of the API there can only be 256 handles.
+ */
+#define SENSORS_HANDLE_BASE 0
+#define SENSORS_HANDLE_BITS 8
+#define SENSORS_HANDLE_COUNT (1<<SENSORS_HANDLE_BITS)
+
+
+/*
+ * flags for (*batch)()
+ * Availability: SENSORS_DEVICE_API_VERSION_1_0
+ * see (*batch)() documentation for details
+ */
+enum
+{
+ SENSORS_BATCH_DRY_RUN = 0x00000001,
+ SENSORS_BATCH_WAKE_UPON_FIFO_FULL = 0x00000002
+};
+
+/*
+ * what field for meta_data_event_t
+ */
+enum
+{
+ /* a previous flush operation has completed */
+ META_DATA_FLUSH_COMPLETE = 1,
+ META_DATA_VERSION /* always last, leave auto-assigned */
+};
+
+/**
+ * Definition of the axis used by the sensor HAL API
+ *
+ * This API is relative to the screen of the device in its default orientation,
+ * that is, if the device can be used in portrait or landscape, this API
+ * is only relative to the NATURAL orientation of the screen. In other words,
+ * the axis are not swapped when the device's screen orientation changes.
+ * Higher level services /may/ perform this transformation.
+ *
+ * x<0 x>0
+ * ^
+ * |
+ * +-----------+--> y>0
+ * | |
+ * | |
+ * | |
+ * | | / z<0
+ * | | /
+ * | | /
+ * O-----------+/
+ * |[] [ ] []/
+ * +----------/+ y<0
+ * /
+ * /
+ * |/ z>0 (toward the sky)
+ *
+ * O: Origin (x=0,y=0,z=0)
+ *
+ */
+
+/*
+ * Interaction with suspend mode
+ *
+ * Unless otherwise noted, an enabled sensor shall not prevent the
+ * SoC to go into suspend mode. It is the responsibility of applications
+ * to keep a partial wake-lock should they wish to receive sensor
+ * events while the screen is off. While in suspend mode, and unless
+ * otherwise noted (batch mode, sensor particularities, ...), enabled sensors'
+ * events are lost.
+ *
+ * Note that conceptually, the sensor itself is not de-activated while in
+ * suspend mode -- it's just that the data it returns are lost. As soon as
+ * the SoC gets out of suspend mode, operations resume as usual. Of course,
+ * in practice sensors shall be disabled while in suspend mode to
+ * save power, unless batch mode is active, in which case they must
+ * continue fill their internal FIFO (see the documentation of batch() to
+ * learn how suspend interacts with batch mode).
+ *
+ * In batch mode, and only when the flag SENSORS_BATCH_WAKE_UPON_FIFO_FULL is
+ * set and supported, the specified sensor must be able to wake-up the SoC and
+ * be able to buffer at least 10 seconds worth of the requested sensor events.
+ *
+ * There are notable exceptions to this behavior, which are sensor-dependent
+ * (see sensor types definitions below)
+ *
+ *
+ * The sensor type documentation below specifies the wake-up behavior of
+ * each sensor:
+ * wake-up: yes this sensor must wake-up the SoC to deliver events
+ * wake-up: no this sensor shall not wake-up the SoC, events are dropped
+ *
+ */
+
+/*
+ * Sensor type
+ *
+ * Each sensor has a type which defines what this sensor measures and how
+ * measures are reported. All types are defined below.
+ *
+ * Device manufacturers (OEMs) can define their own sensor types, for
+ * their private use by applications or services provided by them. Such
+ * sensor types are specific to an OEM and can't be exposed in the SDK.
+ * These types must start at SENSOR_TYPE_DEVICE_PRIVATE_BASE.
+ */
+
+/*
+ * Base for device manufacturers private sensor types.
+ * These sensor types can't be exposed in the SDK.
+ */
+#define SENSOR_TYPE_DEVICE_PRIVATE_BASE 0x10000
+
+/*
+ * Sensor fusion and virtual sensors
+ *
+ * Many sensor types are or can be implemented as virtual sensors from
+ * physical sensors on the device. For instance the rotation vector sensor,
+ * orientation sensor, step-detector, step-counter, etc...
+ *
+ * From the point of view of this API these virtual sensors MUST appear as
+ * real, individual sensors. It is the responsibility of the driver and HAL
+ * to make sure this is the case.
+ *
+ * In particular, all sensors must be able to function concurrently.
+ * For example, if defining both an accelerometer and a step counter,
+ * then both must be able to work concurrently.
+ */
+
+/*
+ * Trigger modes
+ *
+ * Sensors can report events in different ways called trigger modes,
+ * each sensor type has one and only one trigger mode associated to it.
+ * Currently there are four trigger modes defined:
+ *
+ * continuous: events are reported at a constant rate defined by setDelay().
+ * eg: accelerometers, gyroscopes.
+ * on-change: events are reported only if the sensor's value has changed.
+ * setDelay() is used to set a lower limit to the reporting
+ * period (minimum time between two events).
+ * The HAL must return an event immediately when an on-change
+ * sensor is activated.
+ * eg: proximity, light sensors
+ * one-shot: upon detection of an event, the sensor deactivates itself and
+ * then sends a single event. Order matters to avoid race
+ * conditions. No other event is sent until the sensor get
+ * reactivated. setDelay() is ignored.
+ * eg: significant motion sensor
+ * special: see details in the sensor type specification below
+ *
+ */
+
+/*
+ * SENSOR_TYPE_META_DATA
+ * trigger-mode: n/a
+ * wake-up sensor: n/a
+ *
+ * NO SENSOR OF THAT TYPE MUST BE RETURNED (*get_sensors_list)()
+ *
+ * SENSOR_TYPE_META_DATA is a special token used to populate the
+ * sensors_meta_data_event structure. It doesn't correspond to a physical
+ * sensor. sensors_meta_data_event are special, they exist only inside
+ * the HAL and are generated spontaneously, as opposed to be related to
+ * a physical sensor.
+ *
+ * sensors_meta_data_event_t.version must be META_DATA_VERSION
+ * sensors_meta_data_event_t.sensor must be 0
+ * sensors_meta_data_event_t.type must be SENSOR_TYPE_META_DATA
+ * sensors_meta_data_event_t.reserved must be 0
+ * sensors_meta_data_event_t.timestamp must be 0
+ *
+ * The payload is a meta_data_event_t, where:
+ * meta_data_event_t.what can take the following values:
+ *
+ * META_DATA_FLUSH_COMPLETE
+ * This event indicates that a previous (*flush)() call has completed for the sensor
+ * handle specified in meta_data_event_t.sensor.
+ * see (*flush)() for more details
+ *
+ * All other values for meta_data_event_t.what are reserved and
+ * must not be used.
+ *
+ */
+#define SENSOR_TYPE_META_DATA (0)
+
+/*
+ * SENSOR_TYPE_ACCELEROMETER
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * All values are in SI units (m/s^2) and measure the acceleration of the
+ * device minus the force of gravity.
+ *
+ * Acceleration sensors return sensor events for all 3 axes at a constant
+ * rate defined by setDelay().
+ *
+ * x: Acceleration on the x-axis
+ * y: Acceleration on the y-axis
+ * z: Acceleration on the z-axis
+ *
+ * Note that the readings from the accelerometer include the acceleration
+ * due to gravity (which is opposite to the direction of the gravity vector).
+ *
+ * Examples:
+ * The norm of <x, y, z> should be close to 0 when in free fall.
+ *
+ * When the device lies flat on a table and is pushed on its left side
+ * toward the right, the x acceleration value is positive.
+ *
+ * When the device lies flat on a table, the acceleration value is +9.81,
+ * which correspond to the acceleration of the device (0 m/s^2) minus the
+ * force of gravity (-9.81 m/s^2).
+ *
+ * When the device lies flat on a table and is pushed toward the sky, the
+ * acceleration value is greater than +9.81, which correspond to the
+ * acceleration of the device (+A m/s^2) minus the force of
+ * gravity (-9.81 m/s^2).
+ */
+#define SENSOR_TYPE_ACCELEROMETER (1)
+
+/*
+ * SENSOR_TYPE_GEOMAGNETIC_FIELD
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * All values are in micro-Tesla (uT) and measure the geomagnetic
+ * field in the X, Y and Z axis.
+ *
+ * Returned values include calibration mechanisms such that the vector is
+ * aligned with the magnetic declination and heading of the earth's
+ * geomagnetic field.
+ *
+ * Magnetic Field sensors return sensor events for all 3 axes at a constant
+ * rate defined by setDelay().
+ */
+#define SENSOR_TYPE_GEOMAGNETIC_FIELD (2)
+#define SENSOR_TYPE_MAGNETIC_FIELD SENSOR_TYPE_GEOMAGNETIC_FIELD
+
+/*
+ * SENSOR_TYPE_ORIENTATION
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * All values are angles in degrees.
+ *
+ * Orientation sensors return sensor events for all 3 axes at a constant
+ * rate defined by setDelay().
+ *
+ * azimuth: angle between the magnetic north direction and the Y axis, around
+ * the Z axis (0<=azimuth<360).
+ * 0=North, 90=East, 180=South, 270=West
+ *
+ * pitch: Rotation around X axis (-180<=pitch<=180), with positive values when
+ * the z-axis moves toward the y-axis.
+ *
+ * roll: Rotation around Y axis (-90<=roll<=90), with positive values when
+ * the x-axis moves towards the z-axis.
+ *
+ * Note: For historical reasons the roll angle is positive in the clockwise
+ * direction (mathematically speaking, it should be positive in the
+ * counter-clockwise direction):
+ *
+ * Z
+ * ^
+ * (+roll) .--> |
+ * / |
+ * | | roll: rotation around Y axis
+ * X <-------(.)
+ * Y
+ * note that +Y == -roll
+ *
+ *
+ *
+ * Note: This definition is different from yaw, pitch and roll used in aviation
+ * where the X axis is along the long side of the plane (tail to nose).
+ */
+#define SENSOR_TYPE_ORIENTATION (3)
+
+/*
+ * SENSOR_TYPE_GYROSCOPE
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * All values are in radians/second and measure the rate of rotation
+ * around the X, Y and Z axis. The coordinate system is the same as is
+ * used for the acceleration sensor. Rotation is positive in the
+ * counter-clockwise direction (right-hand rule). That is, an observer
+ * looking from some positive location on the x, y or z axis at a device
+ * positioned on the origin would report positive rotation if the device
+ * appeared to be rotating counter clockwise. Note that this is the
+ * standard mathematical definition of positive rotation and does not agree
+ * with the definition of roll given earlier.
+ * The range should at least be 17.45 rad/s (ie: ~1000 deg/s).
+ *
+ * automatic gyro-drift compensation is allowed but not required.
+ */
+#define SENSOR_TYPE_GYROSCOPE (4)
+
+/*
+ * SENSOR_TYPE_LIGHT
+ * trigger-mode: on-change
+ * wake-up sensor: no
+ *
+ * The light sensor value is returned in SI lux units.
+ */
+#define SENSOR_TYPE_LIGHT (5)
+
+/*
+ * SENSOR_TYPE_PRESSURE
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * The pressure sensor return the athmospheric pressure in hectopascal (hPa)
+ */
+#define SENSOR_TYPE_PRESSURE (6)
+
+/* SENSOR_TYPE_TEMPERATURE is deprecated in the HAL */
+#define SENSOR_TYPE_TEMPERATURE (7)
+
+/*
+ * SENSOR_TYPE_PROXIMITY
+ * trigger-mode: on-change
+ * wake-up sensor: yes
+ *
+ * The distance value is measured in centimeters. Note that some proximity
+ * sensors only support a binary "close" or "far" measurement. In this case,
+ * the sensor should report its maxRange value in the "far" state and a value
+ * less than maxRange in the "near" state.
+ */
+#define SENSOR_TYPE_PROXIMITY (8)
+
+/*
+ * SENSOR_TYPE_GRAVITY
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * A gravity output indicates the direction of and magnitude of gravity in
+ * the devices's coordinates. On Earth, the magnitude is 9.8 m/s^2.
+ * Units are m/s^2. The coordinate system is the same as is used for the
+ * acceleration sensor. When the device is at rest, the output of the
+ * gravity sensor should be identical to that of the accelerometer.
+ */
+#define SENSOR_TYPE_GRAVITY (9)
+
+/*
+ * SENSOR_TYPE_LINEAR_ACCELERATION
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * Indicates the linear acceleration of the device in device coordinates,
+ * not including gravity.
+ *
+ * The output is conceptually:
+ * output of TYPE_ACCELERATION - output of TYPE_GRAVITY
+ *
+ * Readings on all axes should be close to 0 when device lies on a table.
+ * Units are m/s^2.
+ * The coordinate system is the same as is used for the acceleration sensor.
+ */
+#define SENSOR_TYPE_LINEAR_ACCELERATION (10)
+
+/*
+ * SENSOR_TYPE_ROTATION_VECTOR
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * The rotation vector symbolizes the orientation of the device relative to the
+ * East-North-Up coordinates frame. It is usually obtained by integration of
+ * accelerometer, gyroscope and magnetometer readings.
+ *
+ * The East-North-Up coordinate system is defined as a direct orthonormal basis
+ * where:
+ * - X points east and is tangential to the ground.
+ * - Y points north and is tangential to the ground.
+ * - Z points towards the sky and is perpendicular to the ground.
+ *
+ * The orientation of the phone is represented by the rotation necessary to
+ * align the East-North-Up coordinates with the phone's coordinates. That is,
+ * applying the rotation to the world frame (X,Y,Z) would align them with the
+ * phone coordinates (x,y,z).
+ *
+ * The rotation can be seen as rotating the phone by an angle theta around
+ * an axis rot_axis to go from the reference (East-North-Up aligned) device
+ * orientation to the current device orientation.
+ *
+ * The rotation is encoded as the 4 (reordered) components of a unit quaternion:
+ * sensors_event_t.data[0] = rot_axis.x*sin(theta/2)
+ * sensors_event_t.data[1] = rot_axis.y*sin(theta/2)
+ * sensors_event_t.data[2] = rot_axis.z*sin(theta/2)
+ * sensors_event_t.data[3] = cos(theta/2)
+ * where
+ * - rot_axis.x,y,z are the North-East-Up coordinates of a unit length vector
+ * representing the rotation axis
+ * - theta is the rotation angle
+ *
+ * The quaternion must be of norm 1 (it is a unit quaternion). Failure to ensure
+ * this will cause erratic client behaviour.
+ *
+ * In addition, this sensor reports an estimated heading accuracy.
+ * sensors_event_t.data[4] = estimated_accuracy (in radians)
+ * The heading error must be less than estimated_accuracy 95% of the time
+ *
+ * This sensor must use a gyroscope and an accelerometer as main orientation
+ * change input.
+ *
+ * This sensor can also include magnetometer input to make up for gyro drift,
+ * but it cannot be implemented using only a magnetometer.
+ */
+#define SENSOR_TYPE_ROTATION_VECTOR (11)
+
+/*
+ * SENSOR_TYPE_RELATIVE_HUMIDITY
+ * trigger-mode: on-change
+ * wake-up sensor: no
+ *
+ * A relative humidity sensor measures relative ambient air humidity and
+ * returns a value in percent.
+ */
+#define SENSOR_TYPE_RELATIVE_HUMIDITY (12)
+
+/*
+ * SENSOR_TYPE_AMBIENT_TEMPERATURE
+ * trigger-mode: on-change
+ * wake-up sensor: no
+ *
+ * The ambient (room) temperature in degree Celsius.
+ */
+#define SENSOR_TYPE_AMBIENT_TEMPERATURE (13)
+
+/*
+ * SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * Similar to SENSOR_TYPE_MAGNETIC_FIELD, but the hard iron calibration is
+ * reported separately instead of being included in the measurement.
+ * Factory calibration and temperature compensation should still be applied to
+ * the "uncalibrated" measurement.
+ * Separating away the hard iron calibration estimation allows the system to
+ * better recover from bad hard iron estimation.
+ *
+ * All values are in micro-Tesla (uT) and measure the ambient magnetic
+ * field in the X, Y and Z axis. Assumptions that the the magnetic field
+ * is due to the Earth's poles should be avoided.
+ *
+ * The uncalibrated_magnetic event contains
+ * - 3 fields for uncalibrated measurement: x_uncalib, y_uncalib, z_uncalib.
+ * Each is a component of the measured magnetic field, with soft iron
+ * and temperature compensation applied, but not hard iron calibration.
+ * These values should be continuous (no re-calibration should cause a jump).
+ * - 3 fields for hard iron bias estimates: x_bias, y_bias, z_bias.
+ * Each field is a component of the estimated hard iron calibration.
+ * They represent the offsets to apply to the calibrated readings to obtain
+ * uncalibrated readings (x_uncalib ~= x_calibrated + x_bias)
+ * These values are expected to jump as soon as the estimate of the hard iron
+ * changes, and they should be stable the rest of the time.
+ *
+ * If this sensor is present, then the corresponding
+ * SENSOR_TYPE_MAGNETIC_FIELD must be present and both must return the
+ * same sensor_t::name and sensor_t::vendor.
+ *
+ * Minimum filtering should be applied to this sensor. In particular, low pass
+ * filters should be avoided.
+ *
+ * See SENSOR_TYPE_MAGNETIC_FIELD for more information
+ */
+#define SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED (14)
+
+/*
+ * SENSOR_TYPE_GAME_ROTATION_VECTOR
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * Similar to SENSOR_TYPE_ROTATION_VECTOR, but not using the geomagnetic
+ * field. Therefore the Y axis doesn't point north, but instead to some other
+ * reference. That reference is allowed to drift by the same order of
+ * magnitude than the gyroscope drift around the Z axis.
+ *
+ * This sensor does not report an estimated heading accuracy:
+ * sensors_event_t.data[4] is reserved and should be set to 0
+ *
+ * In the ideal case, a phone rotated and returning to the same real-world
+ * orientation should report the same game rotation vector
+ * (without using the earth's geomagnetic field).
+ *
+ * This sensor must be based on a gyroscope. It cannot be implemented using
+ * a magnetometer.
+ *
+ * see SENSOR_TYPE_ROTATION_VECTOR for more details
+ */
+#define SENSOR_TYPE_GAME_ROTATION_VECTOR (15)
+
+/*
+ * SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * All values are in radians/second and measure the rate of rotation
+ * around the X, Y and Z axis. An estimation of the drift on each axis is
+ * reported as well.
+ *
+ * No gyro-drift compensation shall be performed.
+ * Factory calibration and temperature compensation should still be applied
+ * to the rate of rotation (angular speeds).
+ *
+ * The coordinate system is the same as is
+ * used for the acceleration sensor. Rotation is positive in the
+ * counter-clockwise direction (right-hand rule). That is, an observer
+ * looking from some positive location on the x, y or z axis at a device
+ * positioned on the origin would report positive rotation if the device
+ * appeared to be rotating counter clockwise. Note that this is the
+ * standard mathematical definition of positive rotation and does not agree
+ * with the definition of roll given earlier.
+ * The range should at least be 17.45 rad/s (ie: ~1000 deg/s).
+ *
+ * Content of an uncalibrated_gyro event: (units are rad/sec)
+ * x_uncalib : angular speed (w/o drift compensation) around the X axis
+ * y_uncalib : angular speed (w/o drift compensation) around the Y axis
+ * z_uncalib : angular speed (w/o drift compensation) around the Z axis
+ * x_bias : estimated drift around X axis in rad/s
+ * y_bias : estimated drift around Y axis in rad/s
+ * z_bias : estimated drift around Z axis in rad/s
+ *
+ * IMPLEMENTATION NOTES:
+ *
+ * If the implementation is not able to estimate the drift, then this
+ * sensor MUST NOT be reported by this HAL. Instead, the regular
+ * SENSOR_TYPE_GYROSCOPE is used without drift compensation.
+ *
+ * If this sensor is present, then the corresponding
+ * SENSOR_TYPE_GYROSCOPE must be present and both must return the
+ * same sensor_t::name and sensor_t::vendor.
+ */
+#define SENSOR_TYPE_GYROSCOPE_UNCALIBRATED (16)
+
+/*
+ * SENSOR_TYPE_SIGNIFICANT_MOTION
+ * trigger-mode: one-shot
+ * wake-up sensor: yes
+ *
+ * A sensor of this type triggers an event each time significant motion
+ * is detected and automatically disables itself.
+ * The only allowed value to return is 1.0.
+ *
+ * A significant motion is a motion that might lead to a change in the user
+ * location.
+ * Examples of such motions are:
+ * walking, biking, sitting in a moving car, coach or train.
+ * Examples of situations that should not trigger significant motion:
+ * - phone in pocket and person is not moving
+ * - phone is on a table, even if the table shakes a bit due to nearby traffic
+ * or washing machine
+ *
+ * A note on false positive / false negative / power consumption tradeoff
+ * - The goal of this sensor is to save power.
+ * - Triggering an event when the user is not moving (false positive) is costly
+ * in terms of power, so it should be avoided.
+ * - Not triggering an event when the user is moving (false negative) is
+ * acceptable as long as it is not done repeatedly. If the user has been
+ * walking for 10 seconds, not triggering an event within those 10 seconds
+ * is not acceptable.
+ *
+ * IMPORTANT NOTE: this sensor type is very different from other types
+ * in that it must work when the screen is off without the need of
+ * holding a partial wake-lock and MUST allow the SoC to go into suspend.
+ * When significant motion is detected, the sensor must awaken the SoC and
+ * the event be reported.
+ *
+ * If a particular hardware cannot support this mode of operation then this
+ * sensor type MUST NOT be reported by the HAL. ie: it is not acceptable
+ * to "emulate" this sensor in the HAL.
+ *
+ * The whole point of this sensor type is to save power by keeping the
+ * SoC in suspend mode when the device is at rest.
+ *
+ * When the sensor is not activated, it must also be deactivated in the
+ * hardware: it must not wake up the SoC anymore, even in case of
+ * significant motion.
+ *
+ * setDelay() has no effect and is ignored.
+ * Once a "significant motion" event is returned, a sensor of this type
+ * must disables itself automatically, as if activate(..., 0) had been called.
+ */
+
+#define SENSOR_TYPE_SIGNIFICANT_MOTION (17)
+
+/*
+ * SENSOR_TYPE_STEP_DETECTOR
+ * trigger-mode: special
+ * wake-up sensor: no
+ *
+ * A sensor of this type triggers an event each time a step is taken
+ * by the user. The only allowed value to return is 1.0 and an event is
+ * generated for each step. Like with any other event, the timestamp
+ * indicates when the event (here the step) occurred, this corresponds to when
+ * the foot hit the ground, generating a high variation in acceleration.
+ *
+ * While this sensor operates, it shall not disrupt any other sensors, in
+ * particular, but not limited to, the accelerometer; which might very well
+ * be in use as well.
+ *
+ * This sensor must be low power. That is, if the step detection cannot be
+ * done in hardware, this sensor should not be defined. Also, when the
+ * step detector is activated and the accelerometer is not, only steps should
+ * trigger interrupts (not accelerometer data).
+ *
+ * setDelay() has no impact on this sensor type
+ */
+
+#define SENSOR_TYPE_STEP_DETECTOR (18)
+
+/*
+ * SENSOR_TYPE_STEP_COUNTER
+ * trigger-mode: on-change
+ * wake-up sensor: no
+ *
+ * A sensor of this type returns the number of steps taken by the user since
+ * the last reboot while activated. The value is returned as a uint64_t and is
+ * reset to zero only on a system / android reboot.
+ *
+ * The timestamp of the event is set to the time when the first step
+ * for that event was taken.
+ * See SENSOR_TYPE_STEP_DETECTOR for the signification of the time of a step.
+ *
+ * The minimum size of the hardware's internal counter shall be 16 bits
+ * (this restriction is here to avoid too frequent wake-ups when the
+ * delay is very large).
+ *
+ * IMPORTANT NOTE: this sensor type is different from other types
+ * in that it must work when the screen is off without the need of
+ * holding a partial wake-lock and MUST allow the SoC to go into suspend.
+ * Unlike other sensors, while in suspend mode this sensor must stay active,
+ * no events are reported during that time but, steps continue to be
+ * accounted for; an event will be reported as soon as the SoC resumes if
+ * the timeout has expired.
+ *
+ * In other words, when the screen is off and the device allowed to
+ * go into suspend mode, we don't want to be woken up, regardless of the
+ * setDelay() value, but the steps shall continue to be counted.
+ *
+ * The driver must however ensure that the internal step count never
+ * overflows. It is allowed in this situation to wake the SoC up so the
+ * driver can do the counter maintenance.
+ *
+ * While this sensor operates, it shall not disrupt any other sensors, in
+ * particular, but not limited to, the accelerometer; which might very well
+ * be in use as well.
+ *
+ * If a particular hardware cannot support these modes of operation then this
+ * sensor type MUST NOT be reported by the HAL. ie: it is not acceptable
+ * to "emulate" this sensor in the HAL.
+ *
+ * This sensor must be low power. That is, if the step detection cannot be
+ * done in hardware, this sensor should not be defined. Also, when the
+ * step counter is activated and the accelerometer is not, only steps should
+ * trigger interrupts (not accelerometer data).
+ *
+ * The whole point of this sensor type is to save power by keeping the
+ * SoC in suspend mode when the device is at rest.
+ */
+
+#define SENSOR_TYPE_STEP_COUNTER (19)
+
+/*
+ * SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ * trigger-mode: continuous
+ * wake-up sensor: no
+ *
+ * Similar to SENSOR_TYPE_ROTATION_VECTOR, but using a magnetometer instead
+ * of using a gyroscope.
+ *
+ * This sensor must be based on a magnetometer. It cannot be implemented using
+ * a gyroscope, and gyroscope input cannot be used by this sensor, as the
+ * goal of this sensor is to be low power.
+ * The accelerometer can be (and usually is) used.
+ *
+ * Just like SENSOR_TYPE_ROTATION_VECTOR, this sensor reports an estimated
+ * heading accuracy:
+ * sensors_event_t.data[4] = estimated_accuracy (in radians)
+ * The heading error must be less than estimated_accuracy 95% of the time
+ *
+ * see SENSOR_TYPE_ROTATION_VECTOR for more details
+ */
+#define SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR (20)
+
+/**
+ * Values returned by the accelerometer in various locations in the universe.
+ * all values are in SI units (m/s^2)
+ */
+#define GRAVITY_SUN (275.0f)
+#define GRAVITY_EARTH (9.80665f)
+
+/** Maximum magnetic field on Earth's surface */
+#define MAGNETIC_FIELD_EARTH_MAX (60.0f)
+
+/** Minimum magnetic field on Earth's surface */
+#define MAGNETIC_FIELD_EARTH_MIN (30.0f)
+
+/**
+ * status of orientation sensor
+ */
+#define SENSOR_STATUS_UNRELIABLE 0
+#define SENSOR_STATUS_ACCURACY_LOW 1
+#define SENSOR_STATUS_ACCURACY_MEDIUM 2
+#define SENSOR_STATUS_ACCURACY_HIGH 3
+
+/**
+ * sensor event data
+ */
+typedef struct
+{
+ union
+ {
+ float v[3];
+ struct
+ {
+ float x;
+ float y;
+ float z;
+ };
+ struct
+ {
+ float azimuth;
+ float pitch;
+ float roll;
+ };
+ };
+ int8_t status;
+ uint8_t reserved[3];
+} sensors_vec_t;
+
+/**
+ * uncalibrated gyroscope and magnetometer event data
+ */
+typedef struct
+{
+ union
+ {
+ float uncalib[3];
+ struct
+ {
+ float x_uncalib;
+ float y_uncalib;
+ float z_uncalib;
+ };
+ };
+ union
+ {
+ float bias[3];
+ struct
+ {
+ float x_bias;
+ float y_bias;
+ float z_bias;
+ };
+ };
+} uncalibrated_event_t;
+
+typedef struct meta_data_event
+{
+ int32_t what;
+ int32_t sensor;
+} meta_data_event_t;
+
+/**
+ * Union of the various types of sensor data
+ * that can be returned.
+ */
+typedef struct sensors_event_t
+{
+ /* must be sizeof(struct sensors_event_t) */
+ int32_t version;
+
+ /* sensor identifier */
+ int32_t sensor;
+
+ /* sensor type */
+ int32_t type;
+
+ /* reserved */
+ int32_t reserved0;
+
+ /* time is in nanosecond */
+ int64_t timestamp;
+
+ union
+ {
+ union
+ {
+ float data[16];
+
+ /* acceleration values are in meter per second per second (m/s^2) */
+ sensors_vec_t acceleration;
+
+ /* magnetic vector values are in micro-Tesla (uT) */
+ sensors_vec_t magnetic;
+
+ /* orientation values are in degrees */
+ sensors_vec_t orientation;
+
+ /* gyroscope values are in rad/s */
+ sensors_vec_t gyro;
+
+ /* temperature is in degrees centigrade (Celsius) */
+ float temperature;
+
+ /* distance in centimeters */
+ float distance;
+
+ /* light in SI lux units */
+ float light;
+
+ /* pressure in hectopascal (hPa) */
+ float pressure;
+
+ /* relative humidity in percent */
+ float relative_humidity;
+
+ /* uncalibrated gyroscope values are in rad/s */
+ uncalibrated_event_t uncalibrated_gyro;
+
+ /* uncalibrated magnetometer values are in micro-Teslas */
+ uncalibrated_event_t uncalibrated_magnetic;
+
+ /* this is a special event. see SENSOR_TYPE_META_DATA above.
+ * sensors_meta_data_event_t events are all reported with a type of
+ * SENSOR_TYPE_META_DATA. The handle is ignored and must be zero.
+ */
+ meta_data_event_t meta_data;
+ };
+
+ union
+ {
+ uint64_t data[8];
+
+ /* step-counter */
+ uint64_t step_counter;
+ } u64;
+ };
+ uint32_t reserved1[4];
+} sensors_event_t;
+
+/* see SENSOR_TYPE_META_DATA */
+typedef sensors_event_t sensors_meta_data_event_t;
+
+typedef struct sensor_t
+{
+
+ /* Name of this sensor.
+ * All sensors of the same "type" must have a different "name".
+ */
+ const char *name;
+
+ /* vendor of the hardware part */
+ const char *vendor;
+
+ /* version of the hardware part + driver. The value of this field
+ * must increase when the driver is updated in a way that changes the
+ * output of this sensor. This is important for fused sensors when the
+ * fusion algorithm is updated.
+ */
+ int version;
+
+ /* handle that identifies this sensors. This handle is used to reference
+ * this sensor throughout the HAL API.
+ */
+ int handle;
+
+ /* this sensor's type. */
+ int type;
+
+ /* maximum range of this sensor's value in SI units */
+ float maxRange;
+
+ /* smallest difference between two values reported by this sensor */
+ float resolution;
+
+ /* rough estimate of this sensor's power consumption in mA */
+ float power;
+
+ /* this value depends on the trigger mode:
+ *
+ * continuous: minimum sample period allowed in microseconds
+ * on-change : 0
+ * one-shot :-1
+ * special : 0, unless otherwise noted
+ */
+ int32_t minDelay;
+
+ /* number of events reserved for this sensor in the batch mode FIFO.
+ * If there is a dedicated FIFO for this sensor, then this is the
+ * size of this FIFO. If the FIFO is shared with other sensors,
+ * this is the size reserved for that sensor and it can be zero.
+ */
+ uint32_t fifoReservedEventCount;
+
+ /* maximum number of events of this sensor that could be batched.
+ * This is especially relevant when the FIFO is shared between
+ * several sensors; this value is then set to the size of that FIFO.
+ */
+ uint32_t fifoMaxEventCount;
+
+ /* reserved fields, must be zero */
+ void *reserved[6];
+} sensor_t;
+
+class SensorConfigure
+{
+ int32_t delay;
+};
+
+class Sensor;
+class SensorManager;
+typedef void (*SensorEventHandler_t)(Sensor *sensor, sensors_event_t *event, void *user_data);
+
+/**
+ * Sensor Base Class
+ */
+class Sensor
+{
+private:
+ int type;
+
+public:
+ Sensor();
+ ~Sensor();
+
+ virtual int Configure(SensorConfigure *config) = 0;
+ virtual int Activate(int enable) = 0;
+
+ virtual int Poll(sensors_event_t *events, int number, int duration) = 0;
+ virtual void GetSensor(struct sensor_t *sensor) = 0;
+
+ int GetType(void);
+
+ int Subscribe(SensorEventHandler_t *handler, void *user_data);
+ int Publish(sensors_event_t *event);
+
+protected:
+ Sensor *next;
+ Sensor *prev;
+
+ SensorEventHandler_t *evtHandler;
+ void *userData;
+
+ friend class SensorManager;
+};
+
+/**
+ * Sensor Manager
+ */
+class SensorManager
+{
+public:
+ SensorManager();
+ ~SensorManager();
+
+ static int RegisterSensor(Sensor *sensor);
+ static int DeregisterSensor(Sensor *sensor);
+
+ static Sensor *GetDefaultSensor(int type);
+ static int Subscribe(int type, SensorEventHandler_t *handler, void *user_data);
+
+private:
+ Sensor *sensorList;
+};
+
+#endif
+
diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c
index 776316baf5..f04b1df4f4 100644
--- a/components/drivers/serial/serial.c
+++ b/components/drivers/serial/serial.c
@@ -37,48 +37,48 @@
*/
rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
{
- int ch;
- int size;
-
- RT_ASSERT(serial != RT_NULL);
- size = length;
+ int ch;
+ int size;
+
+ RT_ASSERT(serial != RT_NULL);
+ size = length;
- while (length)
- {
- ch = serial->ops->getc(serial);
- *data = ch;
- data ++; length --;
+ while (length)
+ {
+ ch = serial->ops->getc(serial);
+ *data = ch;
+ data ++; length --;
- if (ch == '\n') break;
- }
+ if (ch == '\n') break;
+ }
- return size - length;
+ return size - length;
}
rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
{
- int size;
- RT_ASSERT(serial != RT_NULL);
+ int size;
+ RT_ASSERT(serial != RT_NULL);
- size = length;
- while (length)
- {
- /*
- * to be polite with serial console add a line feed
- * to the carriage return character
- */
- if (*data == '\n' && (serial->parent.flag & RT_DEVICE_FLAG_STREAM))
- {
- serial->ops->putc(serial, '\r');
- }
-
- serial->ops->putc(serial, *data);
-
- ++ data;
- -- length;
- }
+ size = length;
+ while (length)
+ {
+ /*
+ * to be polite with serial console add a line feed
+ * to the carriage return character
+ */
+ if (*data == '\n' && (serial->parent.flag & RT_DEVICE_FLAG_STREAM))
+ {
+ serial->ops->putc(serial, '\r');
+ }
+
+ serial->ops->putc(serial, *data);
+
+ ++ data;
+ -- length;
+ }
- return size - length;
+ return size - length;
}
/*
@@ -86,69 +86,69 @@ rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t
*/
rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
{
- int size;
- struct rt_serial_rx_fifo* rx_fifo;
+ int size;
+ struct rt_serial_rx_fifo* rx_fifo;
- RT_ASSERT(serial != RT_NULL);
- size = length;
-
- rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx;
- RT_ASSERT(rx_fifo != RT_NULL);
+ RT_ASSERT(serial != RT_NULL);
+ size = length;
+
+ rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
- /* read from software FIFO */
- while (length)
- {
- int ch;
- rt_base_t level;
+ /* read from software FIFO */
+ while (length)
+ {
+ int ch;
+ rt_base_t level;
- /* disable interrupt */
- level = rt_hw_interrupt_disable();
- if (rx_fifo->get_index != rx_fifo->put_index)
- {
- ch = rx_fifo->buffer[rx_fifo->get_index];
- rx_fifo->get_index += 1;
- if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
- }
- else
- {
- /* no data, enable interrupt and break out */
- rt_hw_interrupt_enable(level);
- break;
- }
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+ if (rx_fifo->get_index != rx_fifo->put_index)
+ {
+ ch = rx_fifo->buffer[rx_fifo->get_index];
+ rx_fifo->get_index += 1;
+ if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
+ }
+ else
+ {
+ /* no data, enable interrupt and break out */
+ rt_hw_interrupt_enable(level);
+ break;
+ }
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
- *data = ch & 0xff;
- data ++; length --;
- }
+ *data = ch & 0xff;
+ data ++; length --;
+ }
- return size - length;
+ return size - length;
}
rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
{
- int size;
- struct rt_serial_tx_fifo *tx;
-
- RT_ASSERT(serial != RT_NULL);
+ int size;
+ struct rt_serial_tx_fifo *tx;
+
+ RT_ASSERT(serial != RT_NULL);
- size = length;
- tx = (struct rt_serial_tx_fifo*) serial->serial_tx;
- RT_ASSERT(tx != RT_NULL);
+ size = length;
+ tx = (struct rt_serial_tx_fifo*) serial->serial_tx;
+ RT_ASSERT(tx != RT_NULL);
- while (length)
- {
- if (serial->ops->putc(serial, *(char*)data) == -1)
- {
- rt_completion_wait(&(tx->completion), RT_WAITING_FOREVER);
- continue;
- }
+ while (length)
+ {
+ if (serial->ops->putc(serial, *(char*)data) == -1)
+ {
+ rt_completion_wait(&(tx->completion), RT_WAITING_FOREVER);
+ continue;
+ }
- data ++; length --;
- }
+ data ++; length --;
+ }
- return size - length;
+ return size - length;
}
/*
@@ -156,61 +156,61 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
*/
rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
{
- rt_base_t level;
- int result = RT_EOK;
- struct rt_serial_rx_dma *rx_dma;
+ rt_base_t level;
+ int result = RT_EOK;
+ struct rt_serial_rx_dma *rx_dma;
- RT_ASSERT((serial != RT_NULL) && (data != RT_NULL));
- rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
- RT_ASSERT(rx_dma != RT_NULL);
+ RT_ASSERT((serial != RT_NULL) && (data != RT_NULL));
+ rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
+ RT_ASSERT(rx_dma != RT_NULL);
- level = rt_hw_interrupt_disable();
- if (rx_dma->activated != RT_TRUE)
- {
- rx_dma->activated = RT_TRUE;
- serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_RX);
- }
- else result = -RT_EBUSY;
- rt_hw_interrupt_enable(level);
+ level = rt_hw_interrupt_disable();
+ if (rx_dma->activated != RT_TRUE)
+ {
+ rx_dma->activated = RT_TRUE;
+ serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_RX);
+ }
+ else result = -RT_EBUSY;
+ rt_hw_interrupt_enable(level);
- if (result == RT_EOK) return length;
+ if (result == RT_EOK) return length;
- rt_set_errno(result);
- return 0;
+ rt_set_errno(result);
+ return 0;
}
rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
{
- rt_base_t level;
- rt_err_t result;
- struct rt_serial_tx_dma *tx_dma;
+ rt_base_t level;
+ rt_err_t result;
+ struct rt_serial_tx_dma *tx_dma;
- tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx);
-
- result = rt_data_queue_push(&(tx_dma->data_queue), data, length, RT_WAITING_FOREVER);
- if (result == RT_EOK)
- {
- level = rt_hw_interrupt_disable();
- if (tx_dma->activated != RT_TRUE)
- {
- tx_dma->activated = RT_TRUE;
- rt_hw_interrupt_enable(level);
+ tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx);
+
+ result = rt_data_queue_push(&(tx_dma->data_queue), data, length, RT_WAITING_FOREVER);
+ if (result == RT_EOK)
+ {
+ level = rt_hw_interrupt_disable();
+ if (tx_dma->activated != RT_TRUE)
+ {
+ tx_dma->activated = RT_TRUE;
+ rt_hw_interrupt_enable(level);
- /* make a DMA transfer */
- serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_TX);
- }
- else
- {
- rt_hw_interrupt_enable(level);
- }
+ /* make a DMA transfer */
+ serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_TX);
+ }
+ else
+ {
+ rt_hw_interrupt_enable(level);
+ }
- return length;
- }
- else
- {
- rt_set_errno(result);
- return 0;
- }
+ return length;
+ }
+ else
+ {
+ rt_set_errno(result);
+ return 0;
+ }
}
/* RT-Thread Device Interface */
@@ -225,15 +225,15 @@ static rt_err_t rt_serial_init(struct rt_device *dev)
RT_ASSERT(dev != RT_NULL);
serial = (struct rt_serial_device *)dev;
- /* initialize rx/tx */
- serial->serial_rx = RT_NULL;
- serial->serial_tx = RT_NULL;
+ /* initialize rx/tx */
+ serial->serial_rx = RT_NULL;
+ serial->serial_tx = RT_NULL;
- /* apply configuration */
- if (serial->ops->configure)
- result = serial->ops->configure(serial, &serial->config);
+ /* apply configuration */
+ if (serial->ops->configure)
+ result = serial->ops->configure(serial, &serial->config);
- return result;
+ return result;
}
static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
@@ -243,89 +243,89 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
RT_ASSERT(dev != RT_NULL);
serial = (struct rt_serial_device *)dev;
- /* check device flag with the open flag */
- if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
- return -RT_EIO;
- if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
- return -RT_EIO;
- if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
- return -RT_EIO;
- if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX))
- return -RT_EIO;
+ /* check device flag with the open flag */
+ if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
+ return -RT_EIO;
+ if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
+ return -RT_EIO;
+ if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
+ return -RT_EIO;
+ if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX))
+ return -RT_EIO;
- /* get open flags */
- dev->open_flag = oflag & 0xff;
-
- /* initialize the Rx/Tx structure according to open flag */
- if (serial->serial_rx == RT_NULL)
- {
- if (oflag & RT_DEVICE_FLAG_DMA_RX)
- {
- struct rt_serial_rx_dma* rx_dma;
+ /* get open flags */
+ dev->open_flag = oflag & 0xff;
+
+ /* initialize the Rx/Tx structure according to open flag */
+ if (serial->serial_rx == RT_NULL)
+ {
+ if (oflag & RT_DEVICE_FLAG_DMA_RX)
+ {
+ struct rt_serial_rx_dma* rx_dma;
- rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma));
- RT_ASSERT(rx_dma != RT_NULL);
- rx_dma->activated = RT_FALSE;
+ rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma));
+ RT_ASSERT(rx_dma != RT_NULL);
+ rx_dma->activated = RT_FALSE;
- serial->serial_rx = rx_dma;
- dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
- }
- else if (oflag & RT_DEVICE_FLAG_INT_RX)
- {
- struct rt_serial_rx_fifo* rx_fifo;
+ serial->serial_rx = rx_dma;
+ dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
+ }
+ else if (oflag & RT_DEVICE_FLAG_INT_RX)
+ {
+ struct rt_serial_rx_fifo* rx_fifo;
- rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
- serial->config.bufsz);
- RT_ASSERT(rx_fifo != RT_NULL);
- rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
- rt_memset(rx_fifo->buffer, 0, RT_SERIAL_RB_BUFSZ);
- rx_fifo->put_index = 0;
- rx_fifo->get_index = 0;
+ rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
+ serial->config.bufsz);
+ RT_ASSERT(rx_fifo != RT_NULL);
+ rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
+ rt_memset(rx_fifo->buffer, 0, RT_SERIAL_RB_BUFSZ);
+ rx_fifo->put_index = 0;
+ rx_fifo->get_index = 0;
- serial->serial_rx = rx_fifo;
- dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
- /* configure low level device */
- serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
- }
- else
- {
- serial->serial_rx = RT_NULL;
- }
- }
+ serial->serial_rx = rx_fifo;
+ dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
+ }
+ else
+ {
+ serial->serial_rx = RT_NULL;
+ }
+ }
- if (serial->serial_tx == RT_NULL)
- {
- if (oflag & RT_DEVICE_FLAG_DMA_TX)
- {
- struct rt_serial_tx_dma* tx_dma;
+ if (serial->serial_tx == RT_NULL)
+ {
+ if (oflag & RT_DEVICE_FLAG_DMA_TX)
+ {
+ struct rt_serial_tx_dma* tx_dma;
- tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
- RT_ASSERT(tx_dma != RT_NULL);
-
- rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
- serial->serial_tx = tx_dma;
+ tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
+ RT_ASSERT(tx_dma != RT_NULL);
+
+ rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
+ serial->serial_tx = tx_dma;
- dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
- }
- else if (oflag & RT_DEVICE_FLAG_INT_TX)
- {
- struct rt_serial_tx_fifo *tx_fifo;
+ dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
+ }
+ else if (oflag & RT_DEVICE_FLAG_INT_TX)
+ {
+ struct rt_serial_tx_fifo *tx_fifo;
- tx_fifo = (struct rt_serial_tx_fifo*) rt_malloc(sizeof(struct rt_serial_tx_fifo));
- RT_ASSERT(tx_fifo != RT_NULL);
+ tx_fifo = (struct rt_serial_tx_fifo*) rt_malloc(sizeof(struct rt_serial_tx_fifo));
+ RT_ASSERT(tx_fifo != RT_NULL);
- rt_completion_init(&(tx_fifo->completion));
- serial->serial_tx = tx_fifo;
+ rt_completion_init(&(tx_fifo->completion));
+ serial->serial_tx = tx_fifo;
- dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
- /* configure low level device */
- serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
- }
- else
- {
- serial->serial_tx = RT_NULL;
- }
- }
+ dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
+ }
+ else
+ {
+ serial->serial_tx = RT_NULL;
+ }
+ }
return RT_EOK;
}
@@ -337,58 +337,58 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
RT_ASSERT(dev != RT_NULL);
serial = (struct rt_serial_device *)dev;
- /* this device has more reference count */
- if (dev->ref_count > 1) return RT_EOK;
-
- if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
- {
- struct rt_serial_rx_fifo* rx_fifo;
+ /* this device has more reference count */
+ if (dev->ref_count > 1) return RT_EOK;
+
+ if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
+ {
+ struct rt_serial_rx_fifo* rx_fifo;
- rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
- RT_ASSERT(rx_fifo != RT_NULL);
+ rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
- rt_free(rx_fifo);
- serial->serial_rx = RT_NULL;
- dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX;
- /* configure low level device */
- serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX);
- }
- else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
- {
- struct rt_serial_rx_dma* rx_dma;
+ rt_free(rx_fifo);
+ serial->serial_rx = RT_NULL;
+ dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX;
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX);
+ }
+ else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
+ {
+ struct rt_serial_rx_dma* rx_dma;
- rx_dma = (struct rt_serial_rx_dma*)serial->serial_tx;
- RT_ASSERT(rx_dma != RT_NULL);
+ rx_dma = (struct rt_serial_rx_dma*)serial->serial_tx;
+ RT_ASSERT(rx_dma != RT_NULL);
- rt_free(rx_dma);
- serial->serial_rx = RT_NULL;
- dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
- }
+ rt_free(rx_dma);
+ serial->serial_rx = RT_NULL;
+ dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
+ }
- if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
- {
- struct rt_serial_tx_fifo* tx_fifo;
+ if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
+ {
+ struct rt_serial_tx_fifo* tx_fifo;
- tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_rx;
- RT_ASSERT(tx_fifo != RT_NULL);
+ tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_rx;
+ RT_ASSERT(tx_fifo != RT_NULL);
- rt_free(tx_fifo);
- serial->serial_tx = RT_NULL;
- dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX;
- /* configure low level device */
- serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX);
- }
- else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
- {
- struct rt_serial_tx_dma* tx_dma;
+ rt_free(tx_fifo);
+ serial->serial_tx = RT_NULL;
+ dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX;
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX);
+ }
+ else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
+ {
+ struct rt_serial_tx_dma* tx_dma;
- tx_dma = (struct rt_serial_tx_dma*)serial->serial_tx;
- RT_ASSERT(tx_dma != RT_NULL);
+ tx_dma = (struct rt_serial_tx_dma*)serial->serial_tx;
+ RT_ASSERT(tx_dma != RT_NULL);
- rt_free(tx_dma);
- serial->serial_tx = RT_NULL;
- dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX;
- }
+ rt_free(tx_dma);
+ serial->serial_tx = RT_NULL;
+ dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX;
+ }
return RT_EOK;
}
@@ -405,16 +405,16 @@ static rt_size_t rt_serial_read(struct rt_device *dev,
serial = (struct rt_serial_device *)dev;
- if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
- {
- return _serial_int_rx(serial, buffer, size);
- }
- else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
- {
- return _serial_dma_rx(serial, buffer, size);
- }
+ if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
+ {
+ return _serial_int_rx(serial, buffer, size);
+ }
+ else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
+ {
+ return _serial_dma_rx(serial, buffer, size);
+ }
- return _serial_poll_rx(serial, buffer, size);
+ return _serial_poll_rx(serial, buffer, size);
}
static rt_size_t rt_serial_write(struct rt_device *dev,
@@ -429,16 +429,18 @@ static rt_size_t rt_serial_write(struct rt_device *dev,
serial = (struct rt_serial_device *)dev;
- if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
- {
- _serial_int_tx(serial, buffer, size);
- }
- else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
- {
- _serial_dma_tx(serial, buffer, size);
- }
-
- return _serial_poll_tx(serial, buffer, size);
+ if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
+ {
+ return _serial_int_tx(serial, buffer, size);
+ }
+ else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
+ {
+ return _serial_dma_tx(serial, buffer, size);
+ }
+ else
+ {
+ return _serial_poll_tx(serial, buffer, size);
+ }
}
static rt_err_t rt_serial_control(struct rt_device *dev,
@@ -508,106 +510,106 @@ rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
/* ISR for serial interrupt */
void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
{
- switch (event & 0xff)
- {
- case RT_SERIAL_EVENT_RX_IND:
- {
- int ch = -1;
- rt_base_t level;
- struct rt_serial_rx_fifo* rx_fifo;
+ switch (event & 0xff)
+ {
+ case RT_SERIAL_EVENT_RX_IND:
+ {
+ int ch = -1;
+ rt_base_t level;
+ struct rt_serial_rx_fifo* rx_fifo;
- rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
- RT_ASSERT(rx_fifo != RT_NULL);
-
- /* interrupt mode receive */
- RT_ASSERT(serial->parent.open_flag & RT_DEVICE_FLAG_INT_RX);
-
- while (1)
- {
- ch = serial->ops->getc(serial);
- if (ch == -1) break;
+ rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
+ RT_ASSERT(rx_fifo != RT_NULL);
+
+ /* interrupt mode receive */
+ RT_ASSERT(serial->parent.open_flag & RT_DEVICE_FLAG_INT_RX);
+
+ while (1)
+ {
+ ch = serial->ops->getc(serial);
+ if (ch == -1) break;
-
- /* disable interrupt */
- level = rt_hw_interrupt_disable();
-
- rx_fifo->buffer[rx_fifo->put_index] = ch;
- rx_fifo->put_index += 1;
- if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;
-
- /* if the next position is read index, discard this 'read char' */
- if (rx_fifo->put_index == rx_fifo->get_index)
- {
- rx_fifo->get_index += 1;
- if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
- }
-
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
- }
-
- /* invoke callback */
- if (serial->parent.rx_indicate != RT_NULL)
- {
- rt_size_t rx_length;
-
- /* get rx length */
- level = rt_hw_interrupt_disable();
- rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
- (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));
- rt_hw_interrupt_enable(level);
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ rx_fifo->buffer[rx_fifo->put_index] = ch;
+ rx_fifo->put_index += 1;
+ if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;
+
+ /* if the next position is read index, discard this 'read char' */
+ if (rx_fifo->put_index == rx_fifo->get_index)
+ {
+ rx_fifo->get_index += 1;
+ if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+ }
+
+ /* invoke callback */
+ if (serial->parent.rx_indicate != RT_NULL)
+ {
+ rt_size_t rx_length;
+
+ /* get rx length */
+ level = rt_hw_interrupt_disable();
+ rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
+ (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));
+ rt_hw_interrupt_enable(level);
- serial->parent.rx_indicate(&serial->parent, rx_length);
- }
- break;
- }
- case RT_SERIAL_EVENT_TX_DONE:
- {
- struct rt_serial_tx_fifo* tx_fifo;
+ serial->parent.rx_indicate(&serial->parent, rx_length);
+ }
+ break;
+ }
+ case RT_SERIAL_EVENT_TX_DONE:
+ {
+ struct rt_serial_tx_fifo* tx_fifo;
- tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx;
- rt_completion_done(&(tx_fifo->completion));
- break;
- }
- case RT_SERIAL_EVENT_TX_DMADONE:
- {
- const void *data_ptr;
- rt_size_t data_size;
- const void *last_data_ptr;
- struct rt_serial_tx_dma* tx_dma;
+ tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx;
+ rt_completion_done(&(tx_fifo->completion));
+ break;
+ }
+ case RT_SERIAL_EVENT_TX_DMADONE:
+ {
+ const void *data_ptr;
+ rt_size_t data_size;
+ const void *last_data_ptr;
+ struct rt_serial_tx_dma* tx_dma;
- tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx;
-
- rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0);
- if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK)
- {
- /* transmit next data node */
- tx_dma->activated = RT_TRUE;
- serial->ops->dma_transmit(serial, data_ptr, data_size, RT_SERIAL_DMA_TX);
- }
- else
- {
- tx_dma->activated = RT_FALSE;
- }
-
- /* invoke callback */
- if (serial->parent.tx_complete != RT_NULL)
- {
- serial->parent.tx_complete(&serial->parent, (void*)last_data_ptr);
- }
- break;
- }
- case RT_SERIAL_EVENT_RX_DMADONE:
- {
- int length;
- struct rt_serial_rx_dma* rx_dma;
+ tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx;
+
+ rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0);
+ if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK)
+ {
+ /* transmit next data node */
+ tx_dma->activated = RT_TRUE;
+ serial->ops->dma_transmit(serial, data_ptr, data_size, RT_SERIAL_DMA_TX);
+ }
+ else
+ {
+ tx_dma->activated = RT_FALSE;
+ }
+
+ /* invoke callback */
+ if (serial->parent.tx_complete != RT_NULL)
+ {
+ serial->parent.tx_complete(&serial->parent, (void*)last_data_ptr);
+ }
+ break;
+ }
+ case RT_SERIAL_EVENT_RX_DMADONE:
+ {
+ int length;
+ struct rt_serial_rx_dma* rx_dma;
- rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
- /* get DMA rx length */
- length = (event & (~0xff)) >> 8;
- serial->parent.rx_indicate(&(serial->parent), length);
- rx_dma->activated = RT_FALSE;
- break;
- }
- }
+ rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
+ /* get DMA rx length */
+ length = (event & (~0xff)) >> 8;
+ serial->parent.rx_indicate(&(serial->parent), length);
+ rx_dma->activated = RT_FALSE;
+ break;
+ }
+ }
}
diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript
index f114ef7a41..1047b8839a 100644
--- a/components/drivers/spi/SConscript
+++ b/components/drivers/spi/SConscript
@@ -1,8 +1,28 @@
from building import *
-cwd = GetCurrentDir()
-src = Glob('*.c')
-CPPPATH = [cwd + '/../include']
+cwd = GetCurrentDir()
+src = ['spi_core.c', 'spi_dev.c']
+CPPPATH = [cwd, cwd + '/../include']
+
+src_device = []
+
+if GetDepend('RT_USING_SPI_WIFI'):
+ src_device += ['spi_wifi_rw009.c']
+
+if GetDepend('RT_USING_W25QXX'):
+ src_device += ['spi_flash_w25qxx.c']
+
+if GetDepend('RT_USING_ENC28J60'):
+ src_device += ['enc28j60.c']
+
+if GetDepend('RT_USING_AT45DBXX'):
+ src_device += ['spi_flash_at45dbxx.c']
+
+if GetDepend('RT_USING_SST25VFXX'):
+ src_device += ['spi_flash_sst25vfxx.c']
+
+src += src_device
+
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH)
Return('group')
diff --git a/components/drivers/spi/device_driver_list.txt b/components/drivers/spi/device_driver_list.txt
new file mode 100644
index 0000000000..2c9d6a16b8
--- /dev/null
+++ b/components/drivers/spi/device_driver_list.txt
@@ -0,0 +1,15 @@
+spi_wifi_rw009.c/spi_wifi_rw009.h
+RW009
+http://www.rt-thread.com/
+
+enc28j60.c/enc28j60.h
+http://www.microchip.com/
+
+spi_flash_at45dbxx.c/spi_flash_at45dbxx.h
+http://www.atmel.com/
+
+spi_flash_sst25vfxx.c/spi_flash_sst25vfxx.h
+http://www.microchip.com/
+
+spi_flash_w25qxx.c/spi_flash_w25qxx.h
+http://www.winbond.com/
diff --git a/components/drivers/spi/enc28j60.c b/components/drivers/spi/enc28j60.c
new file mode 100644
index 0000000000..68f1181dcc
--- /dev/null
+++ b/components/drivers/spi/enc28j60.c
@@ -0,0 +1,876 @@
+#include "enc28j60.h"
+
+#define NET_TRACE
+#define ETH_RX_DUMP
+#define ETH_TX_DUMP
+
+#ifdef NET_TRACE
+#define NET_DEBUG rt_kprintf
+#else
+#define NET_DEBUG(...)
+#endif /* #ifdef NET_TRACE */
+
+struct enc28j60_tx_list_typedef
+{
+ struct enc28j60_tx_list_typedef * prev;
+ struct enc28j60_tx_list_typedef * next;
+ rt_uint32_t addr; /* pkt addr in buffer */
+ rt_uint32_t len; /* pkt len */
+ volatile rt_bool_t free; /* 0:busy, 1:free */
+};
+static struct enc28j60_tx_list_typedef enc28j60_tx_list[2];
+static volatile struct enc28j60_tx_list_typedef * tx_current;
+static volatile struct enc28j60_tx_list_typedef * tx_ack;
+static struct rt_event tx_event;
+
+/* private enc28j60 define */
+/* enc28j60 spi interface function */
+static uint8_t spi_read_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address);
+static void spi_write_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address, uint8_t data);
+
+static uint8_t spi_read(struct rt_spi_device * spi_device, uint8_t address);
+static void spi_write(struct rt_spi_device * spi_device, rt_uint8_t address, rt_uint8_t data);
+
+static void enc28j60_clkout(struct rt_spi_device * spi_device, rt_uint8_t clk);
+static void enc28j60_set_bank(struct rt_spi_device * spi_device, uint8_t address);
+static uint32_t enc28j60_interrupt_disable(struct rt_spi_device * spi_device);
+static void enc28j60_interrupt_enable(struct rt_spi_device * spi_device, uint32_t level);
+
+static uint16_t enc28j60_phy_read(struct rt_spi_device * spi_device, rt_uint8_t address);
+static void enc28j60_phy_write(struct rt_spi_device * spi_device, rt_uint8_t address, uint16_t data);
+static rt_bool_t enc28j60_check_link_status(struct rt_spi_device * spi_device);
+
+#define enc28j60_lock(dev) rt_mutex_take(&((struct net_device*)dev)->lock, RT_WAITING_FOREVER);
+#define enc28j60_unlock(dev) rt_mutex_release(&((struct net_device*)dev)->lock);
+
+static struct net_device enc28j60_dev;
+static uint8_t Enc28j60Bank;
+//struct rt_spi_device * spi_device;
+static uint16_t NextPacketPtr;
+
+static void _delay_us(uint32_t us)
+{
+ volatile uint32_t len;
+ for (; us > 0; us --)
+ for (len = 0; len < 20; len++ );
+}
+
+/* enc28j60 spi interface function */
+static uint8_t spi_read_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address)
+{
+ uint8_t send_buffer[2];
+ uint8_t recv_buffer[1];
+ uint32_t send_size = 1;
+
+ send_buffer[0] = op | (address & ADDR_MASK);
+ send_buffer[1] = 0xFF;
+
+ /* do dummy read if needed (for mac and mii, see datasheet page 29). */
+ if(address & 0x80)
+ {
+ send_size = 2;
+ }
+
+ rt_spi_send_then_recv(spi_device, send_buffer, send_size, recv_buffer, 1);
+ return (recv_buffer[0]);
+}
+
+static void spi_write_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address, uint8_t data)
+{
+ uint32_t level;
+ uint8_t buffer[2];
+
+ level = rt_hw_interrupt_disable();
+
+ buffer[0] = op | (address & ADDR_MASK);
+ buffer[1] = data;
+ rt_spi_send(spi_device, buffer, 2);
+
+ rt_hw_interrupt_enable(level);
+}
+
+/* enc28j60 function */
+static void enc28j60_clkout(struct rt_spi_device * spi_device, rt_uint8_t clk)
+{
+ /* setup clkout: 2 is 12.5MHz: */
+ spi_write(spi_device, ECOCON, clk & 0x7);
+}
+
+static void enc28j60_set_bank(struct rt_spi_device * spi_device, uint8_t address)
+{
+ /* set the bank (if needed) .*/
+ if((address & BANK_MASK) != Enc28j60Bank)
+ {
+ /* set the bank. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
+ Enc28j60Bank = (address & BANK_MASK);
+ }
+}
+
+static uint8_t spi_read(struct rt_spi_device * spi_device, uint8_t address)
+{
+ /* set the bank. */
+ enc28j60_set_bank(spi_device, address);
+ /* do the read. */
+ return spi_read_op(spi_device, ENC28J60_READ_CTRL_REG, address);
+}
+
+static void spi_write(struct rt_spi_device * spi_device, rt_uint8_t address, rt_uint8_t data)
+{
+ /* set the bank. */
+ enc28j60_set_bank(spi_device, address);
+ /* do the write. */
+ spi_write_op(spi_device, ENC28J60_WRITE_CTRL_REG, address, data);
+}
+
+static uint16_t enc28j60_phy_read(struct rt_spi_device * spi_device, rt_uint8_t address)
+{
+ uint16_t value;
+
+ /* Set the right address and start the register read operation. */
+ spi_write(spi_device, MIREGADR, address);
+ spi_write(spi_device, MICMD, MICMD_MIIRD);
+
+ _delay_us(15);
+
+ /* wait until the PHY read completes. */
+ while(spi_read(spi_device, MISTAT) & MISTAT_BUSY);
+
+ /* reset reading bit */
+ spi_write(spi_device, MICMD, 0x00);
+
+ value = spi_read(spi_device, MIRDL) | spi_read(spi_device, MIRDH)<<8;
+
+ return (value);
+}
+
+static void enc28j60_phy_write(struct rt_spi_device * spi_device, rt_uint8_t address, uint16_t data)
+{
+ /* set the PHY register address. */
+ spi_write(spi_device, MIREGADR, address);
+
+ /* write the PHY data. */
+ spi_write(spi_device, MIWRL, data);
+ spi_write(spi_device, MIWRH, data>>8);
+
+ /* wait until the PHY write completes. */
+ while(spi_read(spi_device, MISTAT) & MISTAT_BUSY)
+ {
+ _delay_us(15);
+ }
+}
+
+static uint32_t enc28j60_interrupt_disable(struct rt_spi_device * spi_device)
+{
+ uint32_t level;
+
+ /* switch to bank 0 */
+ enc28j60_set_bank(spi_device, EIE);
+
+ /* get last interrupt level */
+ level = spi_read(spi_device, EIE);
+ /* disable interrutps */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIE, level);
+
+ return level;
+}
+
+static void enc28j60_interrupt_enable(struct rt_spi_device * spi_device, uint32_t level)
+{
+ /* switch to bank 0 */
+ enc28j60_set_bank(spi_device, EIE);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, EIE, level);
+}
+
+/*
+ * Access the PHY to determine link status
+ */
+static rt_bool_t enc28j60_check_link_status(struct rt_spi_device * spi_device)
+{
+ uint16_t reg;
+ int duplex;
+
+ reg = enc28j60_phy_read(spi_device, PHSTAT2);
+ duplex = reg & PHSTAT2_DPXSTAT;
+
+ if (reg & PHSTAT2_LSTAT)
+ {
+ /* on */
+ return RT_TRUE;
+ }
+ else
+ {
+ /* off */
+ return RT_FALSE;
+ }
+}
+
+
+/************************* RT-Thread Device Interface *************************/
+void enc28j60_isr(void)
+{
+ eth_device_ready(&enc28j60_dev.parent);
+ NET_DEBUG("enc28j60_isr\r\n");
+}
+
+static void _tx_chain_init(void)
+{
+ enc28j60_tx_list[0].next = &enc28j60_tx_list[1];
+ enc28j60_tx_list[1].next = &enc28j60_tx_list[0];
+
+ enc28j60_tx_list[0].prev = &enc28j60_tx_list[1];
+ enc28j60_tx_list[1].prev = &enc28j60_tx_list[0];
+
+ enc28j60_tx_list[0].addr = TXSTART_INIT;
+ enc28j60_tx_list[1].addr = TXSTART_INIT + MAX_TX_PACKAGE_SIZE;
+
+ enc28j60_tx_list[0].free = RT_TRUE;
+ enc28j60_tx_list[1].free = RT_TRUE;
+
+ tx_current = &enc28j60_tx_list[0];
+ tx_ack = tx_current;
+}
+
+/* initialize the interface */
+static rt_err_t enc28j60_init(rt_device_t dev)
+{
+ struct net_device * enc28j60 = (struct net_device *)dev;
+ struct rt_spi_device * spi_device = enc28j60->spi_device;
+
+ enc28j60_lock(dev);
+
+ _tx_chain_init();
+
+ // perform system reset
+ spi_write_op(spi_device, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
+ rt_thread_delay(RT_TICK_PER_SECOND/50); /* delay 20ms */
+
+ NextPacketPtr = RXSTART_INIT;
+
+ // Rx start
+ spi_write(spi_device, ERXSTL, RXSTART_INIT&0xFF);
+ spi_write(spi_device, ERXSTH, RXSTART_INIT>>8);
+ // set receive pointer address
+ spi_write(spi_device, ERXRDPTL, RXSTOP_INIT&0xFF);
+ spi_write(spi_device, ERXRDPTH, RXSTOP_INIT>>8);
+ // RX end
+ spi_write(spi_device, ERXNDL, RXSTOP_INIT&0xFF);
+ spi_write(spi_device, ERXNDH, RXSTOP_INIT>>8);
+
+ // TX start
+ spi_write(spi_device, ETXSTL, TXSTART_INIT&0xFF);
+ spi_write(spi_device, ETXSTH, TXSTART_INIT>>8);
+ // set transmission pointer address
+ spi_write(spi_device, EWRPTL, TXSTART_INIT&0xFF);
+ spi_write(spi_device, EWRPTH, TXSTART_INIT>>8);
+ // TX end
+ spi_write(spi_device, ETXNDL, TXSTOP_INIT&0xFF);
+ spi_write(spi_device, ETXNDH, TXSTOP_INIT>>8);
+
+ // do bank 1 stuff, packet filter:
+ // For broadcast packets we allow only ARP packtets
+ // All other packets should be unicast only for our mac (MAADR)
+ //
+ // The pattern to match on is therefore
+ // Type ETH.DST
+ // ARP BROADCAST
+ // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
+ // in binary these poitions are:11 0000 0011 1111
+ // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
+ spi_write(spi_device, ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_BCEN);
+
+ // do bank 2 stuff
+ // enable MAC receive
+ spi_write(spi_device, MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
+ // enable automatic padding to 60bytes and CRC operations
+ // spi_write_op(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
+ // bring MAC out of reset
+
+ // set inter-frame gap (back-to-back)
+ // spi_write(MABBIPG, 0x12);
+ spi_write(spi_device, MABBIPG, 0x15);
+
+ spi_write(spi_device, MACON4, MACON4_DEFER);
+ spi_write(spi_device, MACLCON2, 63);
+
+ // set inter-frame gap (non-back-to-back)
+ spi_write(spi_device, MAIPGL, 0x12);
+ spi_write(spi_device, MAIPGH, 0x0C);
+
+ // Set the maximum packet size which the controller will accept
+ // Do not send packets longer than MAX_FRAMELEN:
+ spi_write(spi_device, MAMXFLL, MAX_FRAMELEN&0xFF);
+ spi_write(spi_device, MAMXFLH, MAX_FRAMELEN>>8);
+
+ // do bank 3 stuff
+ // write MAC address
+ // NOTE: MAC address in ENC28J60 is byte-backward
+ spi_write(spi_device, MAADR0, enc28j60->dev_addr[5]);
+ spi_write(spi_device, MAADR1, enc28j60->dev_addr[4]);
+ spi_write(spi_device, MAADR2, enc28j60->dev_addr[3]);
+ spi_write(spi_device, MAADR3, enc28j60->dev_addr[2]);
+ spi_write(spi_device, MAADR4, enc28j60->dev_addr[1]);
+ spi_write(spi_device, MAADR5, enc28j60->dev_addr[0]);
+
+ /* output off */
+ spi_write(spi_device, ECOCON, 0x00);
+
+ // enc28j60_phy_write(PHCON1, 0x00);
+ enc28j60_phy_write(spi_device, PHCON1, PHCON1_PDPXMD); // full duplex
+ // no loopback of transmitted frames
+ enc28j60_phy_write(spi_device, PHCON2, PHCON2_HDLDIS);
+
+ enc28j60_set_bank(spi_device, ECON2);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON2, ECON2_AUTOINC);
+
+ // switch to bank 0
+ enc28j60_set_bank(spi_device, ECON1);
+ // enable all interrutps
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, EIE, 0xFF);
+ // enable packet reception
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+
+ /* clock out */
+ enc28j60_clkout(spi_device, 2);
+
+ enc28j60_phy_write(spi_device, PHLCON, 0xD76); //0x476
+ rt_thread_delay(RT_TICK_PER_SECOND/50); /* delay 20ms */
+
+ enc28j60_unlock(dev);
+ return RT_EOK;
+}
+
+/* control the interface */
+static rt_err_t enc28j60_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ struct net_device * enc28j60 = (struct net_device *)dev;
+ switch(cmd)
+ {
+ case NIOCTL_GADDR:
+ /* get mac address */
+ if(args) rt_memcpy(args, enc28j60->dev_addr, 6);
+ else return -RT_ERROR;
+ break;
+
+ default :
+ break;
+ }
+
+ return RT_EOK;
+}
+
+/* Open the ethernet interface */
+static rt_err_t enc28j60_open(rt_device_t dev, uint16_t oflag)
+{
+ return RT_EOK;
+}
+
+/* Close the interface */
+static rt_err_t enc28j60_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+/* Read */
+static rt_size_t enc28j60_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return RT_EOK;
+}
+
+/* Write */
+static rt_size_t enc28j60_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+/* ethernet device interface */
+/* Transmit packet. */
+static rt_err_t enc28j60_tx( rt_device_t dev, struct pbuf* p)
+{
+ struct net_device * enc28j60 = (struct net_device *)dev;
+ struct rt_spi_device * spi_device = enc28j60->spi_device;
+ struct pbuf* q;
+ rt_uint32_t level;
+#ifdef ETH_TX_DUMP
+ rt_size_t dump_count = 0;
+ rt_uint8_t * dump_ptr;
+ rt_size_t dump_i;
+#endif
+
+ if(tx_current->free == RT_FALSE)
+ {
+ NET_DEBUG("[Tx] no empty buffer!\r\n");
+ while(tx_current->free == RT_FALSE)
+ {
+ rt_err_t result;
+ rt_uint32_t recved;
+
+ /* there is no block yet, wait a flag */
+ result = rt_event_recv(&tx_event, 0x01,
+ RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &recved);
+
+ RT_ASSERT(result == RT_EOK);
+ }
+ NET_DEBUG("[Tx] wait empty buffer done!\r\n");
+ }
+
+ enc28j60_lock(dev);
+
+ /* disable enc28j60 interrupt */
+ level = enc28j60_interrupt_disable(spi_device);
+
+ // Set the write pointer to start of transmit buffer area
+// spi_write(EWRPTL, TXSTART_INIT&0xFF);
+// spi_write(EWRPTH, TXSTART_INIT>>8);
+ spi_write(spi_device, EWRPTL, (tx_current->addr)&0xFF);
+ spi_write(spi_device, EWRPTH, (tx_current->addr)>>8);
+ // Set the TXND pointer to correspond to the packet size given
+ tx_current->len = p->tot_len;
+// spi_write(ETXNDL, (TXSTART_INIT+ p->tot_len + 1)&0xFF);
+// spi_write(ETXNDH, (TXSTART_INIT+ p->tot_len + 1)>>8);
+
+ // write per-packet control byte (0x00 means use macon3 settings)
+ spi_write_op(spi_device, ENC28J60_WRITE_BUF_MEM, 0, 0x00);
+
+#ifdef ETH_TX_DUMP
+ NET_DEBUG("tx_dump, size:%d\r\n", p->tot_len);
+#endif
+ for (q = p; q != NULL; q = q->next)
+ {
+ uint8_t cmd = ENC28J60_WRITE_BUF_MEM;
+ rt_spi_send_then_send(enc28j60->spi_device, &cmd, 1, q->payload, q->len);
+#ifdef ETH_RX_DUMP
+ dump_ptr = q->payload;
+ for(dump_i=0; dump_i<q->len; dump_i++)
+ {
+ NET_DEBUG("%02x ", *dump_ptr);
+ if( ((dump_count+1)%8) == 0 )
+ {
+ NET_DEBUG(" ");
+ }
+ if( ((dump_count+1)%16) == 0 )
+ {
+ NET_DEBUG("\r\n");
+ }
+ dump_count++;
+ dump_ptr++;
+ }
+#endif
+ }
+#ifdef ETH_RX_DUMP
+ NET_DEBUG("\r\n");
+#endif
+
+ // send the contents of the transmit buffer onto the network
+ if(tx_current == tx_ack)
+ {
+ NET_DEBUG("[Tx] stop, restart!\r\n");
+ // TX start
+ spi_write(spi_device, ETXSTL, (tx_current->addr)&0xFF);
+ spi_write(spi_device, ETXSTH, (tx_current->addr)>>8);
+ // TX end
+ spi_write(spi_device, ETXNDL, (tx_current->addr + tx_current->len)&0xFF);
+ spi_write(spi_device, ETXNDH, (tx_current->addr + tx_current->len)>>8);
+
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
+ }
+ else
+ {
+ NET_DEBUG("[Tx] busy, add to chain!\r\n");
+ }
+
+ tx_current->free = RT_FALSE;
+ tx_current = tx_current->next;
+
+ /* Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. */
+ if( (spi_read(spi_device, EIR) & EIR_TXERIF) )
+ {
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
+ }
+
+ /* enable enc28j60 interrupt */
+ enc28j60_interrupt_enable(spi_device, level);
+
+ enc28j60_unlock(dev);
+
+ return RT_EOK;
+}
+
+/* recv packet. */
+static struct pbuf *enc28j60_rx(rt_device_t dev)
+{
+ struct net_device * enc28j60 = (struct net_device *)dev;
+ struct rt_spi_device * spi_device = enc28j60->spi_device;
+ struct pbuf* p = RT_NULL;
+
+ uint8_t eir, eir_clr;
+ uint32_t pk_counter;
+ rt_uint32_t level;
+ rt_uint32_t len;
+ rt_uint16_t rxstat;
+
+ enc28j60_lock(dev);
+
+ /* disable enc28j60 interrupt */
+ level = enc28j60_interrupt_disable(spi_device);
+
+ /* get EIR */
+ eir = spi_read(spi_device, EIR);
+
+ while(eir & ~EIR_PKTIF)
+ {
+ eir_clr = 0;
+
+ /* clear PKTIF */
+ if (eir & EIR_PKTIF)
+ {
+ NET_DEBUG("EIR_PKTIF\r\n");
+
+ /* switch to bank 0. */
+ enc28j60_set_bank(spi_device, EIE);
+ /* disable rx interrutps. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIE, EIE_PKTIE);
+ eir_clr |= EIR_PKTIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_PKTIF);
+ }
+
+ /* clear DMAIF */
+ if (eir & EIR_DMAIF)
+ {
+ NET_DEBUG("EIR_DMAIF\r\n");
+ eir_clr |= EIR_DMAIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_DMAIF);
+ }
+
+ /* LINK changed handler */
+ if ( eir & EIR_LINKIF)
+ {
+ rt_bool_t link_status;
+
+ NET_DEBUG("EIR_LINKIF\r\n");
+ link_status = enc28j60_check_link_status(spi_device);
+
+ /* read PHIR to clear the flag */
+ enc28j60_phy_read(spi_device, PHIR);
+ eir_clr |= EIR_LINKIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_LINKIF);
+
+ eth_device_linkchange(&(enc28j60->parent), link_status);
+ }
+
+ if (eir & EIR_TXIF)
+ {
+ /* A frame has been transmitted. */
+ enc28j60_set_bank(spi_device, EIR);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXIF);
+
+ tx_ack->free = RT_TRUE;
+ tx_ack = tx_ack->next;
+ if(tx_ack->free == RT_FALSE)
+ {
+ NET_DEBUG("[tx isr] Tx chain not empty, continue send the next pkt!\r\n");
+ // TX start
+ spi_write(spi_device, ETXSTL, (tx_ack->addr)&0xFF);
+ spi_write(spi_device, ETXSTH, (tx_ack->addr)>>8);
+ // TX end
+ spi_write(spi_device, ETXNDL, (tx_ack->addr + tx_ack->len)&0xFF);
+ spi_write(spi_device, ETXNDH, (tx_ack->addr + tx_ack->len)>>8);
+
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
+ }
+ else
+ {
+ NET_DEBUG("[tx isr] Tx chain empty, stop!\r\n");
+ }
+
+ /* set event */
+ rt_event_send(&tx_event, 0x01);
+ }
+
+ /* wake up handler */
+ if ( eir & EIR_WOLIF)
+ {
+ NET_DEBUG("EIR_WOLIF\r\n");
+ eir_clr |= EIR_WOLIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_WOLIF);
+ }
+
+ /* TX Error handler */
+ if ((eir & EIR_TXERIF) != 0)
+ {
+ NET_DEBUG("EIR_TXERIF re-start tx chain!\r\n");
+ enc28j60_set_bank(spi_device, ECON1);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
+ eir_clr |= EIR_TXERIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
+
+ /* re-init tx chain */
+ _tx_chain_init();
+ }
+
+ /* RX Error handler */
+ if ((eir & EIR_RXERIF) != 0)
+ {
+ NET_DEBUG("EIR_RXERIF re-start rx!\r\n");
+
+ NextPacketPtr = RXSTART_INIT;
+ enc28j60_set_bank(spi_device, ECON1);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXRST);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXRST);
+ /* switch to bank 0. */
+ enc28j60_set_bank(spi_device, ECON1);
+ /* enable packet reception. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+ eir_clr |= EIR_RXERIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_RXERIF);
+ }
+
+ enc28j60_set_bank(spi_device, EIR);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, eir_clr);
+
+ eir = spi_read(spi_device, EIR);
+ }
+
+ /* read pkt */
+ pk_counter = spi_read(spi_device, EPKTCNT);
+ if(pk_counter)
+ {
+ /* Set the read pointer to the start of the received packet. */
+ spi_write(spi_device, ERDPTL, (NextPacketPtr));
+ spi_write(spi_device, ERDPTH, (NextPacketPtr)>>8);
+
+ /* read the next packet pointer. */
+ NextPacketPtr = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0);
+ NextPacketPtr |= spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0)<<8;
+
+ /* read the packet length (see datasheet page 43). */
+ len = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0); //0x54
+ len |= spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0)<<8; //5554
+
+ len-=4; //remove the CRC count
+
+ // read the receive status (see datasheet page 43)
+ rxstat = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0);
+ rxstat |= ((rt_uint16_t)spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0))<<8;
+
+ // check CRC and symbol errors (see datasheet page 44, table 7-3):
+ // The ERXFCON.CRCEN is set by default. Normally we should not
+ // need to check this.
+ if ((rxstat & 0x80)==0)
+ {
+ // invalid
+ len=0;
+ }
+ else
+ {
+ /* allocation pbuf */
+ p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM);
+ if (p != RT_NULL)
+ {
+ struct pbuf* q;
+#ifdef ETH_RX_DUMP
+ rt_size_t dump_count = 0;
+ rt_uint8_t * dump_ptr;
+ rt_size_t dump_i;
+ NET_DEBUG("rx_dump, size:%d\r\n", len);
+#endif
+ for (q = p; q != RT_NULL; q= q->next)
+ {
+ uint8_t cmd = ENC28J60_READ_BUF_MEM;
+ rt_spi_send_then_recv(spi_device, &cmd, 1, q->payload, q->len);
+#ifdef ETH_RX_DUMP
+ dump_ptr = q->payload;
+ for(dump_i=0; dump_i<q->len; dump_i++)
+ {
+ NET_DEBUG("%02x ", *dump_ptr);
+ if( ((dump_count+1)%8) == 0 )
+ {
+ NET_DEBUG(" ");
+ }
+ if( ((dump_count+1)%16) == 0 )
+ {
+ NET_DEBUG("\r\n");
+ }
+ dump_count++;
+ dump_ptr++;
+ }
+#endif
+ }
+#ifdef ETH_RX_DUMP
+ NET_DEBUG("\r\n");
+#endif
+ }
+ }
+
+ /* Move the RX read pointer to the start of the next received packet. */
+ /* This frees the memory we just read out. */
+ spi_write(spi_device, ERXRDPTL, (NextPacketPtr));
+ spi_write(spi_device, ERXRDPTH, (NextPacketPtr)>>8);
+
+ /* decrement the packet counter indicate we are done with this packet. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
+ }
+ else
+ {
+ /* switch to bank 0. */
+ enc28j60_set_bank(spi_device, ECON1);
+ /* enable packet reception. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+
+ level |= EIE_PKTIE;
+ }
+
+ /* enable enc28j60 interrupt */
+ enc28j60_interrupt_enable(spi_device, level);
+
+ enc28j60_unlock(dev);
+
+ return p;
+}
+
+rt_err_t enc28j60_attach(const char * spi_device_name)
+{
+ struct rt_spi_device * spi_device;
+
+ spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+ if(spi_device == RT_NULL)
+ {
+ NET_DEBUG("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
+ cfg.max_hz = 20 * 1000 * 1000; /* SPI Interface with Clock Speeds Up to 20 MHz */
+ rt_spi_configure(spi_device, &cfg);
+ } /* config spi */
+
+ memset(&enc28j60_dev, 0, sizeof(enc28j60_dev));
+
+ rt_event_init(&tx_event, "eth_tx", RT_IPC_FLAG_FIFO);
+ enc28j60_dev.spi_device = spi_device;
+
+ /* detect device */
+ {
+ uint16_t value;
+
+ /* perform system reset. */
+ spi_write_op(spi_device, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
+ rt_thread_delay(1); /* delay 20ms */
+
+ enc28j60_dev.emac_rev = spi_read(spi_device, EREVID);
+ value = enc28j60_phy_read(spi_device, PHHID2);
+ enc28j60_dev.phy_rev = value&0x0F;
+ enc28j60_dev.phy_pn = (value>>4)&0x3F;
+ enc28j60_dev.phy_id = (enc28j60_phy_read(spi_device, PHHID1) | ((value>>10)<<16))<<3;
+
+ if(enc28j60_dev.phy_id != 0x00280418)
+ {
+ NET_DEBUG("ENC28J60 PHY ID not correct!\r\n");
+ NET_DEBUG("emac_rev:%d\r\n", enc28j60_dev.emac_rev);
+ NET_DEBUG("phy_rev:%02X\r\n", enc28j60_dev.phy_rev);
+ NET_DEBUG("phy_pn:%02X\r\n", enc28j60_dev.phy_pn);
+ NET_DEBUG("phy_id:%08X\r\n", enc28j60_dev.phy_id);
+ return RT_EIO;
+ }
+ }
+
+ /* OUI 00-04-A3 (hex): Microchip Technology, Inc. */
+ enc28j60_dev.dev_addr[0] = 0x00;
+ enc28j60_dev.dev_addr[1] = 0x04;
+ enc28j60_dev.dev_addr[2] = 0xA3;
+ /* set MAC address, only for test */
+ enc28j60_dev.dev_addr[3] = 0x12;
+ enc28j60_dev.dev_addr[4] = 0x34;
+ enc28j60_dev.dev_addr[5] = 0x56;
+
+ /* init rt-thread device struct */
+ enc28j60_dev.parent.parent.type = RT_Device_Class_NetIf;
+ enc28j60_dev.parent.parent.init = enc28j60_init;
+ enc28j60_dev.parent.parent.open = enc28j60_open;
+ enc28j60_dev.parent.parent.close = enc28j60_close;
+ enc28j60_dev.parent.parent.read = enc28j60_read;
+ enc28j60_dev.parent.parent.write = enc28j60_write;
+ enc28j60_dev.parent.parent.control = enc28j60_control;
+
+ /* init rt-thread ethernet device struct */
+ enc28j60_dev.parent.eth_rx = enc28j60_rx;
+ enc28j60_dev.parent.eth_tx = enc28j60_tx;
+
+ rt_mutex_init(&enc28j60_dev.lock, "enc28j60", RT_IPC_FLAG_FIFO);
+
+ eth_device_init(&(enc28j60_dev.parent), "e0");
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+/*
+ * Debug routine to dump useful register contents
+ */
+static void enc28j60(void)
+{
+ struct rt_spi_device * spi_device = enc28j60_dev.spi_device;
+ enc28j60_lock(&enc28j60_dev);
+
+ rt_kprintf("-- enc28j60 registers:\n");
+ rt_kprintf("HwRevID: 0x%02X\n", spi_read(spi_device, EREVID));
+
+ rt_kprintf("Cntrl: ECON1 ECON2 ESTAT EIR EIE\n");
+ rt_kprintf(" 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
+ spi_read(spi_device, ECON1),
+ spi_read(spi_device, ECON2),
+ spi_read(spi_device, ESTAT),
+ spi_read(spi_device, EIR),
+ spi_read(spi_device, EIE));
+
+ rt_kprintf("MAC : MACON1 MACON3 MACON4\n");
+ rt_kprintf(" 0x%02X 0x%02X 0x%02X\n",
+ spi_read(spi_device, MACON1),
+ spi_read(spi_device, MACON3),
+ spi_read(spi_device, MACON4));
+
+ rt_kprintf("Rx : ERXST ERXND ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\n");
+ rt_kprintf(" 0x%04X 0x%04X 0x%04X 0x%04X ",
+ (spi_read(spi_device, ERXSTH) << 8) | spi_read(spi_device, ERXSTL),
+ (spi_read(spi_device, ERXNDH) << 8) | spi_read(spi_device, ERXNDL),
+ (spi_read(spi_device, ERXWRPTH) << 8) | spi_read(spi_device, ERXWRPTL),
+ (spi_read(spi_device, ERXRDPTH) << 8) | spi_read(spi_device, ERXRDPTL));
+
+ rt_kprintf("0x%02X 0x%02X 0x%04X\n",
+ spi_read(spi_device, ERXFCON),
+ spi_read(spi_device, EPKTCNT),
+ (spi_read(spi_device, MAMXFLH) << 8) | spi_read(spi_device, MAMXFLL));
+
+ rt_kprintf("Tx : ETXST ETXND MACLCON1 MACLCON2 MAPHSUP\n");
+ rt_kprintf(" 0x%04X 0x%04X 0x%02X 0x%02X 0x%02X\n",
+ (spi_read(spi_device, ETXSTH) << 8) | spi_read(spi_device, ETXSTL),
+ (spi_read(spi_device, ETXNDH) << 8) | spi_read(spi_device, ETXNDL),
+ spi_read(spi_device, MACLCON1),
+ spi_read(spi_device, MACLCON2),
+ spi_read(spi_device, MAPHSUP));
+
+ rt_kprintf("PHY : PHCON1 PHSTAT1\r\n");
+ rt_kprintf(" 0x%04X 0x%04X\r\n",
+ enc28j60_phy_read(spi_device, PHCON1),
+ enc28j60_phy_read(spi_device, PHSTAT1));
+
+ enc28j60_unlock(&enc28j60_dev);
+}
+FINSH_FUNCTION_EXPORT(enc28j60, dump enc28j60 registers);
+#endif
diff --git a/components/drivers/spi/enc28j60.h b/components/drivers/spi/enc28j60.h
new file mode 100644
index 0000000000..8c647d5fc2
--- /dev/null
+++ b/components/drivers/spi/enc28j60.h
@@ -0,0 +1,329 @@
+#ifndef EN28J60_H_INCLUDED
+#define EN28J60_H_INCLUDED
+
+#include <stdint.h>
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+#include <netif/ethernetif.h>
+
+// ENC28J60 Control Registers
+// Control register definitions are a combination of address,
+// bank number, and Ethernet/MAC/PHY indicator bits.
+// - Register address (bits 0-4)
+// - Bank number (bits 5-6)
+// - MAC/PHY indicator (bit 7)
+#define ADDR_MASK 0x1F
+#define BANK_MASK 0x60
+#define SPRD_MASK 0x80
+// All-bank registers
+#define EIE 0x1B
+#define EIR 0x1C
+#define ESTAT 0x1D
+#define ECON2 0x1E
+#define ECON1 0x1F
+// Bank 0 registers
+#define ERDPTL (0x00|0x00)
+#define ERDPTH (0x01|0x00)
+#define EWRPTL (0x02|0x00)
+#define EWRPTH (0x03|0x00)
+#define ETXSTL (0x04|0x00)
+#define ETXSTH (0x05|0x00)
+#define ETXNDL (0x06|0x00)
+#define ETXNDH (0x07|0x00)
+#define ERXSTL (0x08|0x00)
+#define ERXSTH (0x09|0x00)
+#define ERXNDL (0x0A|0x00)
+#define ERXNDH (0x0B|0x00)
+#define ERXRDPTL (0x0C|0x00)
+#define ERXRDPTH (0x0D|0x00)
+#define ERXWRPTL (0x0E|0x00)
+#define ERXWRPTH (0x0F|0x00)
+#define EDMASTL (0x10|0x00)
+#define EDMASTH (0x11|0x00)
+#define EDMANDL (0x12|0x00)
+#define EDMANDH (0x13|0x00)
+#define EDMADSTL (0x14|0x00)
+#define EDMADSTH (0x15|0x00)
+#define EDMACSL (0x16|0x00)
+#define EDMACSH (0x17|0x00)
+// Bank 1 registers
+#define EHT0 (0x00|0x20)
+#define EHT1 (0x01|0x20)
+#define EHT2 (0x02|0x20)
+#define EHT3 (0x03|0x20)
+#define EHT4 (0x04|0x20)
+#define EHT5 (0x05|0x20)
+#define EHT6 (0x06|0x20)
+#define EHT7 (0x07|0x20)
+#define EPMM0 (0x08|0x20)
+#define EPMM1 (0x09|0x20)
+#define EPMM2 (0x0A|0x20)
+#define EPMM3 (0x0B|0x20)
+#define EPMM4 (0x0C|0x20)
+#define EPMM5 (0x0D|0x20)
+#define EPMM6 (0x0E|0x20)
+#define EPMM7 (0x0F|0x20)
+#define EPMCSL (0x10|0x20)
+#define EPMCSH (0x11|0x20)
+#define EPMOL (0x14|0x20)
+#define EPMOH (0x15|0x20)
+#define EWOLIE (0x16|0x20)
+#define EWOLIR (0x17|0x20)
+#define ERXFCON (0x18|0x20)
+#define EPKTCNT (0x19|0x20)
+// Bank 2 registers
+#define MACON1 (0x00|0x40|0x80)
+#define MACON2 (0x01|0x40|0x80)
+#define MACON3 (0x02|0x40|0x80)
+#define MACON4 (0x03|0x40|0x80)
+#define MABBIPG (0x04|0x40|0x80)
+#define MAIPGL (0x06|0x40|0x80)
+#define MAIPGH (0x07|0x40|0x80)
+#define MACLCON1 (0x08|0x40|0x80)
+#define MACLCON2 (0x09|0x40|0x80)
+#define MAMXFLL (0x0A|0x40|0x80)
+#define MAMXFLH (0x0B|0x40|0x80)
+#define MAPHSUP (0x0D|0x40|0x80)
+#define MICON (0x11|0x40|0x80)
+#define MICMD (0x12|0x40|0x80)
+#define MIREGADR (0x14|0x40|0x80)
+#define MIWRL (0x16|0x40|0x80)
+#define MIWRH (0x17|0x40|0x80)
+#define MIRDL (0x18|0x40|0x80)
+#define MIRDH (0x19|0x40|0x80)
+// Bank 3 registers
+#define MAADR1 (0x00|0x60|0x80)
+#define MAADR0 (0x01|0x60|0x80)
+#define MAADR3 (0x02|0x60|0x80)
+#define MAADR2 (0x03|0x60|0x80)
+#define MAADR5 (0x04|0x60|0x80)
+#define MAADR4 (0x05|0x60|0x80)
+#define EBSTSD (0x06|0x60)
+#define EBSTCON (0x07|0x60)
+#define EBSTCSL (0x08|0x60)
+#define EBSTCSH (0x09|0x60)
+#define MISTAT (0x0A|0x60|0x80)
+#define EREVID (0x12|0x60)
+#define ECOCON (0x15|0x60)
+#define EFLOCON (0x17|0x60)
+#define EPAUSL (0x18|0x60)
+#define EPAUSH (0x19|0x60)
+// PHY registers
+#define PHCON1 0x00
+#define PHSTAT1 0x01
+#define PHHID1 0x02
+#define PHHID2 0x03
+#define PHCON2 0x10
+#define PHSTAT2 0x11
+#define PHIE 0x12
+#define PHIR 0x13
+#define PHLCON 0x14
+
+// ENC28J60 ERXFCON Register Bit Definitions
+#define ERXFCON_UCEN 0x80
+#define ERXFCON_ANDOR 0x40
+#define ERXFCON_CRCEN 0x20
+#define ERXFCON_PMEN 0x10
+#define ERXFCON_MPEN 0x08
+#define ERXFCON_HTEN 0x04
+#define ERXFCON_MCEN 0x02
+#define ERXFCON_BCEN 0x01
+// ENC28J60 EIE Register Bit Definitions
+#define EIE_INTIE 0x80
+#define EIE_PKTIE 0x40
+#define EIE_DMAIE 0x20
+#define EIE_LINKIE 0x10
+#define EIE_TXIE 0x08
+#define EIE_WOLIE 0x04
+#define EIE_TXERIE 0x02
+#define EIE_RXERIE 0x01
+// ENC28J60 EIR Register Bit Definitions
+#define EIR_PKTIF 0x40
+#define EIR_DMAIF 0x20
+#define EIR_LINKIF 0x10
+#define EIR_TXIF 0x08
+#define EIR_WOLIF 0x04
+#define EIR_TXERIF 0x02
+#define EIR_RXERIF 0x01
+// ENC28J60 ESTAT Register Bit Definitions
+#define ESTAT_INT 0x80
+#define ESTAT_LATECOL 0x10
+#define ESTAT_RXBUSY 0x04
+#define ESTAT_TXABRT 0x02
+#define ESTAT_CLKRDY 0x01
+// ENC28J60 ECON2 Register Bit Definitions
+#define ECON2_AUTOINC 0x80
+#define ECON2_PKTDEC 0x40
+#define ECON2_PWRSV 0x20
+#define ECON2_VRPS 0x08
+// ENC28J60 ECON1 Register Bit Definitions
+#define ECON1_TXRST 0x80
+#define ECON1_RXRST 0x40
+#define ECON1_DMAST 0x20
+#define ECON1_CSUMEN 0x10
+#define ECON1_TXRTS 0x08
+#define ECON1_RXEN 0x04
+#define ECON1_BSEL1 0x02
+#define ECON1_BSEL0 0x01
+// ENC28J60 MACON1 Register Bit Definitions
+#define MACON1_LOOPBK 0x10
+#define MACON1_TXPAUS 0x08
+#define MACON1_RXPAUS 0x04
+#define MACON1_PASSALL 0x02
+#define MACON1_MARXEN 0x01
+// ENC28J60 MACON2 Register Bit Definitions
+#define MACON2_MARST 0x80
+#define MACON2_RNDRST 0x40
+#define MACON2_MARXRST 0x08
+#define MACON2_RFUNRST 0x04
+#define MACON2_MATXRST 0x02
+#define MACON2_TFUNRST 0x01
+// ENC28J60 MACON3 Register Bit Definitions
+#define MACON3_PADCFG2 0x80
+#define MACON3_PADCFG1 0x40
+#define MACON3_PADCFG0 0x20
+#define MACON3_TXCRCEN 0x10
+#define MACON3_PHDRLEN 0x08
+#define MACON3_HFRMLEN 0x04
+#define MACON3_FRMLNEN 0x02
+#define MACON3_FULDPX 0x01
+// ENC28J60 MACON4 Register Bit Definitions
+#define MACON4_DEFER (1<<6)
+#define MACON4_BPEN (1<<5)
+#define MACON4_NOBKOFF (1<<4)
+// ENC28J60 MICMD Register Bit Definitions
+#define MICMD_MIISCAN 0x02
+#define MICMD_MIIRD 0x01
+// ENC28J60 MISTAT Register Bit Definitions
+#define MISTAT_NVALID 0x04
+#define MISTAT_SCAN 0x02
+#define MISTAT_BUSY 0x01
+// ENC28J60 PHY PHCON1 Register Bit Definitions
+#define PHCON1_PRST 0x8000
+#define PHCON1_PLOOPBK 0x4000
+#define PHCON1_PPWRSV 0x0800
+#define PHCON1_PDPXMD 0x0100
+// ENC28J60 PHY PHSTAT1 Register Bit Definitions
+#define PHSTAT1_PFDPX 0x1000
+#define PHSTAT1_PHDPX 0x0800
+#define PHSTAT1_LLSTAT 0x0004
+#define PHSTAT1_JBSTAT 0x0002
+/* ENC28J60 PHY PHSTAT2 Register Bit Definitions */
+#define PHSTAT2_TXSTAT (1 << 13)
+#define PHSTAT2_RXSTAT (1 << 12)
+#define PHSTAT2_COLSTAT (1 << 11)
+#define PHSTAT2_LSTAT (1 << 10)
+#define PHSTAT2_DPXSTAT (1 << 9)
+#define PHSTAT2_PLRITY (1 << 5)
+// ENC28J60 PHY PHCON2 Register Bit Definitions
+#define PHCON2_FRCLINK 0x4000
+#define PHCON2_TXDIS 0x2000
+#define PHCON2_JABBER 0x0400
+#define PHCON2_HDLDIS 0x0100
+
+// ENC28J60 Packet Control Byte Bit Definitions
+#define PKTCTRL_PHUGEEN 0x08
+#define PKTCTRL_PPADEN 0x04
+#define PKTCTRL_PCRCEN 0x02
+#define PKTCTRL_POVERRIDE 0x01
+
+/* ENC28J60 Transmit Status Vector */
+#define TSV_TXBYTECNT 0
+#define TSV_TXCOLLISIONCNT 16
+#define TSV_TXCRCERROR 20
+#define TSV_TXLENCHKERROR 21
+#define TSV_TXLENOUTOFRANGE 22
+#define TSV_TXDONE 23
+#define TSV_TXMULTICAST 24
+#define TSV_TXBROADCAST 25
+#define TSV_TXPACKETDEFER 26
+#define TSV_TXEXDEFER 27
+#define TSV_TXEXCOLLISION 28
+#define TSV_TXLATECOLLISION 29
+#define TSV_TXGIANT 30
+#define TSV_TXUNDERRUN 31
+#define TSV_TOTBYTETXONWIRE 32
+#define TSV_TXCONTROLFRAME 48
+#define TSV_TXPAUSEFRAME 49
+#define TSV_BACKPRESSUREAPP 50
+#define TSV_TXVLANTAGFRAME 51
+
+#define TSV_SIZE 7
+#define TSV_BYTEOF(x) ((x) / 8)
+#define TSV_BITMASK(x) (1 << ((x) % 8))
+#define TSV_GETBIT(x, y) (((x)[TSV_BYTEOF(y)] & TSV_BITMASK(y)) ? 1 : 0)
+
+/* ENC28J60 Receive Status Vector */
+#define RSV_RXLONGEVDROPEV 16
+#define RSV_CARRIEREV 18
+#define RSV_CRCERROR 20
+#define RSV_LENCHECKERR 21
+#define RSV_LENOUTOFRANGE 22
+#define RSV_RXOK 23
+#define RSV_RXMULTICAST 24
+#define RSV_RXBROADCAST 25
+#define RSV_DRIBBLENIBBLE 26
+#define RSV_RXCONTROLFRAME 27
+#define RSV_RXPAUSEFRAME 28
+#define RSV_RXUNKNOWNOPCODE 29
+#define RSV_RXTYPEVLAN 30
+
+#define RSV_SIZE 6
+#define RSV_BITMASK(x) (1 << ((x) - 16))
+#define RSV_GETBIT(x, y) (((x) & RSV_BITMASK(y)) ? 1 : 0)
+
+// SPI operation codes
+#define ENC28J60_READ_CTRL_REG 0x00
+#define ENC28J60_READ_BUF_MEM 0x3A
+#define ENC28J60_WRITE_CTRL_REG 0x40
+#define ENC28J60_WRITE_BUF_MEM 0x7A
+#define ENC28J60_BIT_FIELD_SET 0x80
+#define ENC28J60_BIT_FIELD_CLR 0xA0
+#define ENC28J60_SOFT_RESET 0xFF
+
+// The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata
+// buffer boundaries applied to internal 8K ram
+// the entire available packet buffer space is allocated
+//
+
+#define MAX_TX_PACKAGE_SIZE (1536)
+
+// start with recbuf at 0/
+#define RXSTART_INIT 0x0
+// receive buffer end
+#define RXSTOP_INIT (0x1FFF - MAX_TX_PACKAGE_SIZE*2) - 1
+// start TX buffer at 0x1FFF-0x0600, pace for one full ethernet frame (~1500 bytes)
+
+#define TXSTART_INIT (0x1FFF - MAX_TX_PACKAGE_SIZE*2)
+// stp TX buffer at end of mem
+#define TXSTOP_INIT 0x1FFF
+
+// max frame length which the conroller will accept:
+#define MAX_FRAMELEN 1518
+
+#define MAX_ADDR_LEN 6
+
+struct net_device
+{
+ /* inherit from ethernet device */
+ struct eth_device parent;
+
+ /* interface address info. */
+ rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
+
+ rt_uint8_t emac_rev;
+ rt_uint8_t phy_rev;
+ rt_uint8_t phy_pn;
+ rt_uint32_t phy_id;
+
+ /* spi device */
+ struct rt_spi_device * spi_device;
+ struct rt_mutex lock;
+};
+
+/* export function */
+extern rt_err_t enc28j60_attach(const char * spi_device_name);
+extern void enc28j60_isr(void);
+
+#endif // EN28J60_H_INCLUDED
diff --git a/components/drivers/spi/spi_dev.c b/components/drivers/spi/spi_dev.c
index b1f6e41a86..375a5e0fa1 100644
--- a/components/drivers/spi/spi_dev.c
+++ b/components/drivers/spi/spi_dev.c
@@ -25,16 +25,6 @@
#include <drivers/spi.h>
/* SPI bus device interface, compatible with RT-Thread 0.3.x/1.0.x */
-static rt_err_t _spi_bus_device_init(rt_device_t dev)
-{
- struct rt_spi_bus *bus;
-
- bus = (struct rt_spi_bus *)dev;
- RT_ASSERT(bus != RT_NULL);
-
- return RT_EOK;
-}
-
static rt_size_t _spi_bus_device_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
@@ -67,11 +57,7 @@ static rt_err_t _spi_bus_device_control(rt_device_t dev,
rt_uint8_t cmd,
void *args)
{
- struct rt_spi_bus *bus;
-
- bus = (struct rt_spi_bus *)dev;
- RT_ASSERT(bus != RT_NULL);
-
+ /* TODO: add control command handle */
switch (cmd)
{
case 0: /* set device */
@@ -93,7 +79,7 @@ rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name)
/* set device type */
device->type = RT_Device_Class_SPIBUS;
/* initialize device interface */
- device->init = _spi_bus_device_init;
+ device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = _spi_bus_device_read;
@@ -105,16 +91,6 @@ rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name)
}
/* SPI Dev device interface, compatible with RT-Thread 0.3.x/1.0.x */
-static rt_err_t _spidev_device_init(rt_device_t dev)
-{
- struct rt_spi_device *device;
-
- device = (struct rt_spi_device *)dev;
- RT_ASSERT(device != RT_NULL);
-
- return RT_EOK;
-}
-
static rt_size_t _spidev_device_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
@@ -147,11 +123,6 @@ static rt_err_t _spidev_device_control(rt_device_t dev,
rt_uint8_t cmd,
void *args)
{
- struct rt_spi_device *device;
-
- device = (struct rt_spi_device *)dev;
- RT_ASSERT(device != RT_NULL);
-
switch (cmd)
{
case 0: /* set device */
@@ -172,7 +143,7 @@ rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name)
/* set device type */
device->type = RT_Device_Class_SPIDevice;
- device->init = _spidev_device_init;
+ device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = _spidev_device_read;
diff --git a/components/drivers/spi/spi_flash_at45dbxx.c b/components/drivers/spi/spi_flash_at45dbxx.c
new file mode 100644
index 0000000000..be474f7c65
--- /dev/null
+++ b/components/drivers/spi/spi_flash_at45dbxx.c
@@ -0,0 +1,437 @@
+/*
+ * File : rtdef.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ */
+
+#include <stdint.h>
+#include "spi_flash_at45dbxx.h"
+
+#define FLASH_DEBUG
+#define DMA_BUFFER_SIZE 512
+
+#ifdef FLASH_DEBUG
+#define FLASH_TRACE rt_kprintf
+#else
+#define FLASH_TRACE(...)
+#endif /**< #ifdef FLASH_DEBUG */
+
+/* JEDEC Manufacturer��s ID */
+#define MF_ID (0x1F) /* atmel */
+#define DENSITY_CODE_011D (0x02) /* AT45DB011D Density Code : 00010 = 1-Mbit */
+#define DENSITY_CODE_021D (0x03) /* AT45DB021D Density Code : 00011 = 2-Mbit */
+#define DENSITY_CODE_041D (0x04) /* AT45DB041D Density Code : 00100 = 4-Mbit */
+#define DENSITY_CODE_081D (0x05) /* AT45DB081D Density Code : 00101 = 8-Mbit */
+#define DENSITY_CODE_161D (0x06) /* AT45DB161D Density Code : 00110 = 16-Mbit */
+#define DENSITY_CODE_321D (0x07) /* AT45DB321D Density Code : 00111 = 32-Mbit */
+#define DENSITY_CODE_642D (0x08) /* AT45DB642D Density Code : 01000 = 64-Mbit */
+
+struct JEDEC_ID
+{
+ uint8_t manufacturer_id; /* Manufacturer ID */
+ uint8_t density_code:5; /* Density Code */
+ uint8_t family_code:3; /* Family Code */
+ uint8_t version_code:5; /* Product Version Code */
+ uint8_t mlc_code:3; /* MLC Code */
+ uint8_t byte_count; /* Byte Count */
+};
+
+#define AT45DB_BUFFER_1_WRITE 0x84
+#define AT45DB_BUFFER_2_WRITE 0x87
+#define AT45DB_BUFFER_1_READ 0xD4
+#define AT45DB_BUFFER_2_READ 0xD6
+#define AT45DB_B1_TO_MM_PAGE_PROG_WITH_ERASE 0x83
+#define AT45DB_B2_TO_MM_PAGE_PROG_WITH_ERASE 0x86
+#define AT45DB_MM_PAGE_TO_B1_XFER 0x53
+#define AT45DB_MM_PAGE_TO_B2_XFER 0x55
+#define AT45DB_PAGE_ERASE 0x81
+#define AT45DB_SECTOR_ERASE 0x7C
+#define AT45DB_READ_STATE_REGISTER 0xD7
+#define AT45DB_MM_PAGE_READ 0xD2
+#define AT45DB_MM_PAGE_PROG_THRU_BUFFER1 0x82
+#define AT45DB_CMD_JEDEC_ID 0x9F
+
+static struct spi_flash_at45dbxx spi_flash_at45dbxx;
+
+/*****************************************************************************/
+/*Status Register Format: */
+/* ------------------------------------------------------------------------- */
+/* | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | */
+/* |--------|--------|--------|--------|--------|--------|--------|--------| */
+/* |RDY/BUSY| COMP | device density | X | X | */
+/* ------------------------------------------------------------------------- */
+/* 0:busy | | AT45DB041:0111 | protect|page size */
+/* 1:ready | | AT45DB161:1011 | */
+/* --------------------------------------------------------------------------*/
+/*****************************************************************************/
+static uint8_t AT45DB_StatusRegisterRead(void)
+{
+ return rt_spi_sendrecv8(spi_flash_at45dbxx.rt_spi_device, AT45DB_READ_STATE_REGISTER);
+}
+
+static void wait_busy(void)
+{
+ uint16_t i = 0;
+ while (i++ < 10000)
+ {
+ if (AT45DB_StatusRegisterRead() & 0x80)
+ {
+ return;
+ }
+ }
+ FLASH_TRACE("\r\nSPI_FLASH timeout!!!\r\n");
+}
+
+/* RT-Thread Device Driver Interface */
+static rt_err_t AT45DB_flash_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t AT45DB_flash_open(rt_device_t dev, rt_uint16_t oflag)
+{
+
+ return RT_EOK;
+}
+
+static rt_err_t AT45DB_flash_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t AT45DB_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ RT_ASSERT(dev != RT_NULL);
+
+ if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+ {
+ struct rt_device_blk_geometry *geometry;
+
+ geometry = (struct rt_device_blk_geometry *)args;
+ if (geometry == RT_NULL) return -RT_ERROR;
+
+ geometry->bytes_per_sector = 512;
+ geometry->sector_count = 4096;
+ geometry->block_size = 4096; /* block erase: 4k */
+ }
+
+ return RT_EOK;
+}
+
+static rt_size_t AT45DB_flash_read_page_256(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ uint32_t index, nr;
+ uint8_t * read_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[8];
+ uint32_t i;
+
+ for(i=0; i<sizeof(send_buffer); i++)
+ {
+ send_buffer[i] = 0;
+ }
+
+ send_buffer[0] = AT45DB_MM_PAGE_READ;
+ send_buffer[1] = (uint8_t)(page >> 7);
+ send_buffer[2] = (uint8_t)(page << 1);
+
+ rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 256);
+ read_buffer += 256;
+ page++;
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_read_page_512(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ uint32_t index, nr;
+ uint8_t * read_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[8];
+ uint32_t i;
+
+ for(i=0; i<sizeof(send_buffer); i++)
+ {
+ send_buffer[i] = 0;
+ }
+
+ send_buffer[0] = AT45DB_MM_PAGE_READ;
+ send_buffer[1] = (uint8_t)(page >> 6);
+ send_buffer[2] = (uint8_t)(page << 2);
+
+ rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 512);
+ read_buffer += 512;
+ page++;
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_read_page_1024(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ uint32_t index, nr;
+ uint8_t * read_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[8];
+ uint32_t i;
+
+ for(i=0; i<sizeof(send_buffer); i++)
+ {
+ send_buffer[i] = 0;
+ }
+
+ send_buffer[0] = AT45DB_MM_PAGE_READ;
+ send_buffer[1] = (uint8_t)(page >> 5);
+ send_buffer[2] = (uint8_t)(page << 3);
+
+ rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 1024);
+ read_buffer += 1024;
+ page++;
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_write_page_256(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_uint32_t index, nr;
+ const uint8_t * write_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[4];
+
+ send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1;
+ send_buffer[1] = (uint8_t) (page >> 7);
+ send_buffer[2] = (uint8_t) (page << 1);
+ send_buffer[3] = 0;
+
+ rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 256);
+
+ write_buffer += 256;
+ page++;
+
+ wait_busy();
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_write_page_512(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_uint32_t index, nr;
+ const uint8_t * write_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[4];
+
+ send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1;
+ send_buffer[1] = (uint8_t) (page >> 6);
+ send_buffer[2] = (uint8_t) (page << 2);
+ send_buffer[3] = 0;
+
+ rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 512);
+
+ write_buffer += 512;
+ page++;
+
+ wait_busy();
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_write_page_1024(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_uint32_t index, nr;
+ const uint8_t * write_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[4];
+
+ send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1;
+ send_buffer[1] = (uint8_t) (page >> 5);
+ send_buffer[2] = (uint8_t) (page << 3);
+ send_buffer[3] = 0;
+
+ rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 1024);
+
+ write_buffer += 1024;
+ page++;
+
+ wait_busy();
+ }
+
+ return size;
+}
+
+rt_err_t at45dbxx_init(const char * flash_device_name, const char * spi_device_name)
+{
+ struct rt_spi_device * rt_spi_device;
+ struct JEDEC_ID * JEDEC_ID;
+
+ rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+ if(rt_spi_device == RT_NULL)
+ {
+ FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+ spi_flash_at45dbxx.rt_spi_device = rt_spi_device;
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 and 3 */
+ cfg.max_hz = 66000000; /* Atmel RapidS Serial Interface: 66MHz Maximum Clock Frequency */
+ rt_spi_configure(spi_flash_at45dbxx.rt_spi_device, &cfg);
+ }
+
+ /* read JEDEC ID */
+ {
+ uint8_t cmd;
+ uint8_t id_recv[6];
+ JEDEC_ID = (struct JEDEC_ID *)id_recv;
+
+ cmd = AT45DB_CMD_JEDEC_ID;
+ rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, &cmd, 1, id_recv, 6);
+
+ /**< 1FH = Atmel */
+ /**< 001 = Atmel DataFlash */
+ if(JEDEC_ID->manufacturer_id != 0x1F || JEDEC_ID->family_code != 0x01)
+ {
+ FLASH_TRACE("Manufacturer��s ID or Memory Type error!\r\n");
+ FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
+ return -RT_ENOSYS;
+ }
+
+ if(JEDEC_ID->density_code == DENSITY_CODE_011D)
+ {
+ /**< AT45DB011D Density Code : 00010 = 1-Mbit */
+ FLASH_TRACE("AT45DB011D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 512; /* 1-Mbit / 8 / 256 = 512 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_021D)
+ {
+ /**< AT45DB021D Density Code : 00011 = 2-Mbit */
+ FLASH_TRACE("AT45DB021D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 512*2; /* 2-Mbit / 8 / 256 = 1024 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_041D)
+ {
+ /**< AT45DB041D Density Code : 00100 = 4-Mbit */
+ FLASH_TRACE("AT45DB041D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 512*4; /* 4-Mbit / 8 / 256 = 2048 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_081D)
+ {
+ /**< AT45DB081D Density Code : 00101 = 8-Mbit */
+ FLASH_TRACE("AT45DB081D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 512*8; /* 8-Mbit / 8 / 256 = 4096 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_161D)
+ {
+ /**< AT45DB161D Density Code : 00110 = 16-Mbit */
+ FLASH_TRACE("AT45DB161D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 512; /* Page Erase (512 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 256*16; /* 16-Mbit / 8 / 512 = 4096 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*4; /* Block Erase (4-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_321D)
+ {
+ /**< AT45DB321D Density Code : 00111 = 32-Mbit */
+ FLASH_TRACE("AT45DB321D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 512; /* Page Erase (512 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 256*32; /* 32-Mbit / 8 / 512 = 8192 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*4; /* Block Erase (4-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_642D)
+ {
+ /**< AT45DB642D Density Code : 01000 = 64-Mbit */
+ FLASH_TRACE("AT45DB642D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 1024; /* Page Erase (1 Kbyte) */
+ spi_flash_at45dbxx.geometry.sector_count = 128*64; /* 64-Mbit / 8 / 1024 = 8192 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*8; /* Block Erase (8 Kbytes) */
+ }
+ else
+ {
+ FLASH_TRACE("Memory Capacity error!\r\n");
+ return -RT_ENOSYS;
+ }
+ }
+
+ /* register device */
+ spi_flash_at45dbxx.flash_device.type = RT_Device_Class_Block;
+ spi_flash_at45dbxx.flash_device.init = AT45DB_flash_init;
+ spi_flash_at45dbxx.flash_device.open = AT45DB_flash_open;
+ spi_flash_at45dbxx.flash_device.close = AT45DB_flash_close;
+ spi_flash_at45dbxx.flash_device.control = AT45DB_flash_control;
+
+ if(JEDEC_ID->density_code == DENSITY_CODE_642D)
+ {
+ spi_flash_at45dbxx.flash_device.read = AT45DB_flash_read_page_1024;
+ spi_flash_at45dbxx.flash_device.write = AT45DB_flash_write_page_1024;
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_161D
+ || JEDEC_ID->density_code == DENSITY_CODE_321D )
+ {
+ spi_flash_at45dbxx.flash_device.read = AT45DB_flash_read_page_512;
+ spi_flash_at45dbxx.flash_device.write = AT45DB_flash_write_page_512;
+ }
+ else
+ {
+ spi_flash_at45dbxx.flash_device.read = AT45DB_flash_read_page_256;
+ spi_flash_at45dbxx.flash_device.write = AT45DB_flash_write_page_256;
+ }
+
+ /* no private */
+ spi_flash_at45dbxx.flash_device.user_data = RT_NULL;
+
+ rt_device_register(&spi_flash_at45dbxx.flash_device, flash_device_name,
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+ return RT_EOK;
+}
diff --git a/components/drivers/spi/spi_flash_at45dbxx.h b/components/drivers/spi/spi_flash_at45dbxx.h
new file mode 100644
index 0000000000..9b72cf0a0f
--- /dev/null
+++ b/components/drivers/spi/spi_flash_at45dbxx.h
@@ -0,0 +1,17 @@
+#ifndef SPI_FLASH_AT45DBXX_H_INCLUDED
+#define SPI_FLASH_AT45DBXX_H_INCLUDED
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+struct spi_flash_at45dbxx
+{
+ struct rt_device flash_device;
+ struct rt_device_blk_geometry geometry;
+ struct rt_spi_device * rt_spi_device;
+};
+
+extern rt_err_t at45dbxx_init(const char * flash_device_name, const char * spi_device_name);
+
+
+#endif // SPI_FLASH_AT45DBXX_H_INCLUDED
diff --git a/components/drivers/spi/spi_flash_sst25vfxx.c b/components/drivers/spi/spi_flash_sst25vfxx.c
new file mode 100644
index 0000000000..f0e28b5584
--- /dev/null
+++ b/components/drivers/spi/spi_flash_sst25vfxx.c
@@ -0,0 +1,346 @@
+/*
+ * File : rtdef.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ */
+
+#include <stdint.h>
+#include "spi_flash_sst25vfxx.h"
+
+#define FLASH_DEBUG
+
+#ifdef FLASH_DEBUG
+#define FLASH_TRACE rt_kprintf
+#else
+#define FLASH_TRACE(...)
+#endif /* #ifdef FLASH_DEBUG */
+
+/* JEDEC Manufacturer��s ID */
+#define MF_ID (0xBF)
+/* JEDEC Device ID : Memory Type */
+#define MT_ID (0x25)
+/* JEDEC Device ID: Memory Capacity */
+#define MC_ID_SST25VF020B (0x8C) /* 2Mbit */
+#define MC_ID_SST25VF040B (0x8D) /* 4Mbit */
+#define MC_ID_SST25VF080B (0x8E) /* 8Mbit */
+#define MC_ID_SST25VF016B (0x41) /* 16Mbit */
+#define MC_ID_SST25VF032B (0x4A) /* 32Mbit */
+#define MC_ID_SST25VF064C (0x4B) /* 64Mbit */
+
+/* command list */
+#define CMD_RDSR (0x05)
+#define CMD_WRSR (0x01)
+#define CMD_EWSR (0x50)
+#define CMD_WRDI (0x04)
+#define CMD_WREN (0x06)
+#define CMD_READ (0x03)
+#define CMD_FAST_READ (0x0B)
+#define CMD_BP (0x02)
+#define CMD_AAIP (0xAD)
+#define CMD_ERASE_4K (0x20)
+#define CMD_ERASE_32K (0x52)
+#define CMD_ERASE_64K (0xD8)
+#define CMD_ERASE_full (0xC7)
+#define CMD_JEDEC_ID (0x9F)
+#define CMD_EBSY (0x70)
+#define CMD_DBSY (0x80)
+
+#define DUMMY (0xFF)
+
+static struct spi_flash_sst25vfxx spi_flash_sst25vfxx;
+
+static uint8_t sst25vfxx_read_status(struct spi_flash_sst25vfxx * spi_flash)
+{
+ return rt_spi_sendrecv8(spi_flash->rt_spi_device, CMD_RDSR);
+}
+
+static void sst25vfxx_wait_busy(struct spi_flash_sst25vfxx * spi_flash)
+{
+ while( sst25vfxx_read_status(spi_flash) & (0x01));
+}
+
+/** \brief write N page on [page]
+ *
+ * \param page uint32_t unit : byte (4096 * N,1 page = 4096byte)
+ * \param buffer const uint8_t*
+ * \param size uint32_t unit : byte ( 4096*N )
+ * \return uint32_t
+ *
+ */
+static uint32_t sst25vfxx_page_write(struct spi_flash_sst25vfxx * spi_flash, uint32_t page, const uint8_t * buffer, uint32_t size)
+{
+ uint32_t index;
+ uint32_t need_wirte = size;
+ uint8_t send_buffer[6];
+
+ page &= ~0xFFF; // page size = 4096byte
+
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_ERASE_4K;
+ send_buffer[1] = (page >> 16);
+ send_buffer[2] = (page >> 8);
+ send_buffer[3] = (page);
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 4);
+
+ sst25vfxx_wait_busy(spi_flash); // wait erase done.
+
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_AAIP;
+ send_buffer[1] = (uint8_t)(page >> 16);
+ send_buffer[2] = (uint8_t)(page >> 8);
+ send_buffer[3] = (uint8_t)(page);
+ send_buffer[4] = *buffer++;
+ send_buffer[5] = *buffer++;
+ need_wirte -= 2;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 6);
+
+ sst25vfxx_wait_busy(spi_flash);
+
+ for(index=0; index < need_wirte/2; index++)
+ {
+ send_buffer[0] = CMD_AAIP;
+ send_buffer[1] = *buffer++;
+ send_buffer[2] = *buffer++;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 3);
+ sst25vfxx_wait_busy(spi_flash);
+ }
+
+ send_buffer[0] = CMD_WRDI;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ return size;
+}
+
+/* RT-Thread device interface */
+static rt_err_t sst25vfxx_flash_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t sst25vfxx_flash_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ rt_err_t result;
+ uint8_t send_buffer[2];
+ struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
+
+ /* lock spi flash */
+ result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
+ if(result != RT_EOK)
+ {
+ return result;
+ }
+
+ send_buffer[0] = CMD_DBSY;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_EWSR;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_WRSR;
+ send_buffer[1] = 0;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 2);
+
+ /* release lock */
+ rt_mutex_release(&(spi_flash->lock));
+
+ return RT_EOK;
+}
+
+static rt_err_t sst25vfxx_flash_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t sst25vfxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ struct spi_flash_sst25vfxx * spi_flash;
+
+ spi_flash = (struct spi_flash_sst25vfxx *)dev;
+
+ RT_ASSERT(dev != RT_NULL);
+
+ if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+ {
+ struct rt_device_blk_geometry *geometry;
+
+ geometry = (struct rt_device_blk_geometry *)args;
+ if (geometry == RT_NULL) return -RT_ERROR;
+
+ geometry->bytes_per_sector = spi_flash->geometry.bytes_per_sector;
+ geometry->sector_count = spi_flash->geometry.sector_count;
+ geometry->block_size = spi_flash->geometry.block_size;
+ }
+
+ return RT_EOK;
+}
+
+static rt_size_t sst25vfxx_flash_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ rt_err_t result;
+ uint8_t send_buffer[4];
+ struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
+ uint32_t offset = pos * spi_flash->geometry.bytes_per_sector;
+
+ /* lock spi flash */
+ result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
+ if(result != RT_EOK)
+ {
+ return 0;
+ }
+
+ send_buffer[0] = CMD_WRDI;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_READ;
+ send_buffer[1] = (uint8_t)(offset>>16);
+ send_buffer[2] = (uint8_t)(offset>>8);
+ send_buffer[3] = (uint8_t)(offset);
+ rt_spi_send_then_recv(spi_flash->rt_spi_device, send_buffer, 4, buffer, size * spi_flash->geometry.bytes_per_sector);
+
+ /* release lock */
+ rt_mutex_release(&(spi_flash->lock));
+
+ return size;
+}
+
+static rt_size_t sst25vfxx_flash_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ uint32_t i;
+ rt_err_t result;
+ const uint8_t * write_buffer = buffer;
+ struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
+
+ /* lock spi flash */
+ result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
+ if(result != RT_EOK)
+ {
+ return 0;
+ }
+
+ for(i=0; i<size; i++)
+ {
+ sst25vfxx_page_write(spi_flash,
+ (pos + i) * spi_flash->geometry.bytes_per_sector,
+ write_buffer,
+ spi_flash->geometry.bytes_per_sector);
+ write_buffer += spi_flash->geometry.bytes_per_sector;
+ }
+
+ /* release lock */
+ rt_mutex_release(&(spi_flash->lock));
+
+ return size;
+}
+
+rt_err_t sst25vfxx_init(const char * flash_device_name, const char * spi_device_name)
+{
+ struct rt_spi_device * rt_spi_device;
+ struct spi_flash_sst25vfxx * spi_flash = &spi_flash_sst25vfxx;
+
+ rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+ if(rt_spi_device == RT_NULL)
+ {
+ FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+ spi_flash->rt_spi_device = rt_spi_device;
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+ cfg.max_hz = 50000000; /* 50M */
+ rt_spi_configure(spi_flash->rt_spi_device, &cfg);
+ }
+
+ /* init flash */
+ {
+ rt_uint8_t cmd;
+ rt_uint8_t id_recv[3];
+
+ cmd = CMD_WRDI;
+ rt_spi_send(spi_flash->rt_spi_device, &cmd, 1);
+
+ /* read flash id */
+ cmd = CMD_JEDEC_ID;
+ rt_spi_send_then_recv(spi_flash->rt_spi_device, &cmd, 1, id_recv, 3);
+
+ if(id_recv[0] != MF_ID || id_recv[1] != MT_ID)
+ {
+ FLASH_TRACE("Manufacturer��s ID or Memory Type error!\r\n");
+ FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
+ return -RT_ENOSYS;
+ }
+
+ spi_flash->geometry.bytes_per_sector = 4096;
+ spi_flash->geometry.block_size = 4096; /* block erase: 4k */
+
+ if(id_recv[2] == MC_ID_SST25VF020B)
+ {
+ FLASH_TRACE("SST25VF020B detection\r\n");
+ spi_flash->geometry.sector_count = 64;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF040B)
+ {
+ FLASH_TRACE("SST25VF040B detection\r\n");
+ spi_flash->geometry.sector_count = 128;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF080B)
+ {
+ FLASH_TRACE("SST25VF080B detection\r\n");
+ spi_flash->geometry.sector_count = 256;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF016B)
+ {
+ FLASH_TRACE("SST25VF016B detection\r\n");
+ spi_flash->geometry.sector_count = 512;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF032B)
+ {
+ FLASH_TRACE("SST25VF032B detection\r\n");
+ spi_flash->geometry.sector_count = 1024;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF064C)
+ {
+ FLASH_TRACE("SST25VF064C detection\r\n");
+ spi_flash->geometry.sector_count = 2048;
+ }
+ else
+ {
+ FLASH_TRACE("Memory Capacity error!\r\n");
+ return -RT_ENOSYS;
+ }
+ }
+
+ /* initialize mutex lock */
+ rt_mutex_init(&spi_flash->lock, flash_device_name, RT_IPC_FLAG_PRIO);
+
+ /* register device */
+ spi_flash->flash_device.type = RT_Device_Class_Block;
+ spi_flash->flash_device.init = sst25vfxx_flash_init;
+ spi_flash->flash_device.open = sst25vfxx_flash_open;
+ spi_flash->flash_device.close = sst25vfxx_flash_close;
+ spi_flash->flash_device.read = sst25vfxx_flash_read;
+ spi_flash->flash_device.write = sst25vfxx_flash_write;
+ spi_flash->flash_device.control = sst25vfxx_flash_control;
+ /* no private */
+ spi_flash->flash_device.user_data = RT_NULL;
+
+ rt_device_register(&spi_flash->flash_device, flash_device_name,
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+ return RT_EOK;
+}
diff --git a/components/drivers/spi/spi_flash_sst25vfxx.h b/components/drivers/spi/spi_flash_sst25vfxx.h
new file mode 100644
index 0000000000..b4575c2b68
--- /dev/null
+++ b/components/drivers/spi/spi_flash_sst25vfxx.h
@@ -0,0 +1,32 @@
+/*
+ * File : rtdef.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ */
+
+#ifndef SPI_FLASH_SST25VFXX_H_INCLUDED
+#define SPI_FLASH_SST25VFXX_H_INCLUDED
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+struct spi_flash_sst25vfxx
+{
+ struct rt_device flash_device;
+ struct rt_device_blk_geometry geometry;
+ struct rt_spi_device * rt_spi_device;
+ struct rt_mutex lock;
+};
+
+extern rt_err_t sst25vfxx_init(const char * flash_device_name, const char * spi_device_name);
+
+
+#endif // SPI_FLASH_SST25VFXX_H_INCLUDED
diff --git a/components/drivers/spi/spi_flash_w25qxx.c b/components/drivers/spi/spi_flash_w25qxx.c
new file mode 100644
index 0000000000..bdcdbd83c1
--- /dev/null
+++ b/components/drivers/spi/spi_flash_w25qxx.c
@@ -0,0 +1,371 @@
+/*
+ * File : spi_flash_w25qxx.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ * 2012-05-06 aozima can page write.
+ * 2012-08-23 aozima add flash lock.
+ * 2012-08-24 aozima fixed write status register BUG.
+ */
+
+#include <stdint.h>
+#include "spi_flash_w25qxx.h"
+
+#define FLASH_DEBUG
+
+#ifdef FLASH_DEBUG
+#define FLASH_TRACE rt_kprintf
+#else
+#define FLASH_TRACE(...)
+#endif /* #ifdef FLASH_DEBUG */
+
+#define PAGE_SIZE 4096
+
+/* JEDEC Manufacturer��s ID */
+#define MF_ID (0xEF)
+/* JEDEC Device ID: Memory type and Capacity */
+#define MTC_W25Q16_BV_CL_CV (0x4015) /* W25Q16BV W25Q16CL W25Q16CV */
+#define MTC_W25Q16_DW (0x6015) /* W25Q16DW */
+#define MTC_W25Q32_BV (0x4016) /* W25Q32BV */
+#define MTC_W25Q32_DW (0x6016) /* W25Q32DW */
+#define MTC_W25Q64_BV_CV (0x4017) /* W25Q64BV W25Q64CV */
+#define MTC_W25Q64_DW (0x4017) /* W25Q64DW */
+#define MTC_W25Q128_BV (0x4018) /* W25Q128BV */
+#define MTC_W25Q256_FV (TBD) /* W25Q256FV */
+
+/* command list */
+#define CMD_WRSR (0x01) /* Write Status Register */
+#define CMD_PP (0x02) /* Page Program */
+#define CMD_READ (0x03) /* Read Data */
+#define CMD_WRDI (0x04) /* Write Disable */
+#define CMD_RDSR1 (0x05) /* Read Status Register-1 */
+#define CMD_WREN (0x06) /* Write Enable */
+#define CMD_FAST_READ (0x0B) /* Fast Read */
+#define CMD_ERASE_4K (0x20) /* Sector Erase:4K */
+#define CMD_RDSR2 (0x35) /* Read Status Register-2 */
+#define CMD_ERASE_32K (0x52) /* 32KB Block Erase */
+#define CMD_JEDEC_ID (0x9F) /* Read JEDEC ID */
+#define CMD_ERASE_full (0xC7) /* Chip Erase */
+#define CMD_ERASE_64K (0xD8) /* 64KB Block Erase */
+
+#define DUMMY (0xFF)
+
+static struct spi_flash_device spi_flash_device;
+
+static void flash_lock(struct spi_flash_device * flash_device)
+{
+ rt_mutex_take(&flash_device->lock, RT_WAITING_FOREVER);
+}
+
+static void flash_unlock(struct spi_flash_device * flash_device)
+{
+ rt_mutex_release(&flash_device->lock);
+}
+
+static uint8_t w25qxx_read_status(void)
+{
+ return rt_spi_sendrecv8(spi_flash_device.rt_spi_device, CMD_RDSR1);
+}
+
+static void w25qxx_wait_busy(void)
+{
+ while( w25qxx_read_status() & (0x01));
+}
+
+/** \brief read [size] byte from [offset] to [buffer]
+ *
+ * \param offset uint32_t unit : byte
+ * \param buffer uint8_t*
+ * \param size uint32_t unit : byte
+ * \return uint32_t byte for read
+ *
+ */
+static uint32_t w25qxx_read(uint32_t offset, uint8_t * buffer, uint32_t size)
+{
+ uint8_t send_buffer[4];
+
+ send_buffer[0] = CMD_WRDI;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_READ;
+ send_buffer[1] = (uint8_t)(offset>>16);
+ send_buffer[2] = (uint8_t)(offset>>8);
+ send_buffer[3] = (uint8_t)(offset);
+
+ rt_spi_send_then_recv(spi_flash_device.rt_spi_device,
+ send_buffer, 4,
+ buffer, size);
+
+ return size;
+}
+
+/** \brief write N page on [page]
+ *
+ * \param page_addr uint32_t unit : byte (4096 * N,1 page = 4096byte)
+ * \param buffer const uint8_t*
+ * \return uint32_t
+ *
+ */
+uint32_t w25qxx_page_write(uint32_t page_addr, const uint8_t* buffer)
+{
+ uint32_t index;
+ uint8_t send_buffer[4];
+
+ RT_ASSERT((page_addr&0xFF) == 0); /* page addr must align to 256byte. */
+
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_ERASE_4K;
+ send_buffer[1] = (page_addr >> 16);
+ send_buffer[2] = (page_addr >> 8);
+ send_buffer[3] = (page_addr);
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 4);
+
+ w25qxx_wait_busy(); // wait erase done.
+
+ for(index=0; index < (PAGE_SIZE / 256); index++)
+ {
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_PP;
+ send_buffer[1] = (uint8_t)(page_addr >> 16);
+ send_buffer[2] = (uint8_t)(page_addr >> 8);
+ send_buffer[3] = (uint8_t)(page_addr);
+
+ rt_spi_send_then_send(spi_flash_device.rt_spi_device,
+ send_buffer,
+ 4,
+ buffer,
+ 256);
+
+ buffer += 256;
+ page_addr += 256;
+ w25qxx_wait_busy();
+ }
+
+ send_buffer[0] = CMD_WRDI;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ return PAGE_SIZE;
+}
+
+/* RT-Thread device interface */
+static rt_err_t w25qxx_flash_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t w25qxx_flash_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ uint8_t send_buffer[3];
+
+ flash_lock((struct spi_flash_device *)dev);
+
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_WRSR;
+ send_buffer[1] = 0;
+ send_buffer[2] = 0;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 3);
+
+ w25qxx_wait_busy();
+
+ flash_unlock((struct spi_flash_device *)dev);
+
+ return RT_EOK;
+}
+
+static rt_err_t w25qxx_flash_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t w25qxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ RT_ASSERT(dev != RT_NULL);
+
+ if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+ {
+ struct rt_device_blk_geometry *geometry;
+
+ geometry = (struct rt_device_blk_geometry *)args;
+ if (geometry == RT_NULL) return -RT_ERROR;
+
+ geometry->bytes_per_sector = spi_flash_device.geometry.bytes_per_sector;
+ geometry->sector_count = spi_flash_device.geometry.sector_count;
+ geometry->block_size = spi_flash_device.geometry.block_size;
+ }
+
+ return RT_EOK;
+}
+
+static rt_size_t w25qxx_flash_read(rt_device_t dev,
+ rt_off_t pos,
+ void* buffer,
+ rt_size_t size)
+{
+ flash_lock((struct spi_flash_device *)dev);
+
+ w25qxx_read(pos*spi_flash_device.geometry.bytes_per_sector,
+ buffer,
+ size*spi_flash_device.geometry.bytes_per_sector);
+
+ flash_unlock((struct spi_flash_device *)dev);
+
+ return size;
+}
+
+static rt_size_t w25qxx_flash_write(rt_device_t dev,
+ rt_off_t pos,
+ const void* buffer,
+ rt_size_t size)
+{
+ rt_size_t i = 0;
+ rt_size_t block = size;
+ const uint8_t * ptr = buffer;
+
+ flash_lock((struct spi_flash_device *)dev);
+
+ while(block--)
+ {
+ w25qxx_page_write((pos + i)*spi_flash_device.geometry.bytes_per_sector,
+ ptr);
+ ptr += PAGE_SIZE;
+ i++;
+ }
+
+ flash_unlock((struct spi_flash_device *)dev);
+
+ return size;
+}
+
+rt_err_t w25qxx_init(const char * flash_device_name, const char * spi_device_name)
+{
+ struct rt_spi_device * rt_spi_device;
+
+ /* initialize mutex */
+ if (rt_mutex_init(&spi_flash_device.lock, spi_device_name, RT_IPC_FLAG_FIFO) != RT_EOK)
+ {
+ rt_kprintf("init sd lock mutex failed\n");
+ return -RT_ENOSYS;
+ }
+
+ rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+ if(rt_spi_device == RT_NULL)
+ {
+ FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+ spi_flash_device.rt_spi_device = rt_spi_device;
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+ cfg.max_hz = 50 * 1000 * 1000; /* 50M */
+ rt_spi_configure(spi_flash_device.rt_spi_device, &cfg);
+ }
+
+ /* init flash */
+ {
+ rt_uint8_t cmd;
+ rt_uint8_t id_recv[3];
+ uint16_t memory_type_capacity;
+
+ flash_lock(&spi_flash_device);
+
+ cmd = 0xFF; /* reset SPI FLASH, cancel all cmd in processing. */
+ rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
+
+ cmd = CMD_WRDI;
+ rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
+
+ /* read flash id */
+ cmd = CMD_JEDEC_ID;
+ rt_spi_send_then_recv(spi_flash_device.rt_spi_device, &cmd, 1, id_recv, 3);
+
+ flash_unlock(&spi_flash_device);
+
+ if(id_recv[0] != MF_ID)
+ {
+ FLASH_TRACE("Manufacturers ID error!\r\n");
+ FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
+ return -RT_ENOSYS;
+ }
+
+ spi_flash_device.geometry.bytes_per_sector = 4096;
+ spi_flash_device.geometry.block_size = 4096; /* block erase: 4k */
+
+ /* get memory type and capacity */
+ memory_type_capacity = id_recv[1];
+ memory_type_capacity = (memory_type_capacity << 8) | id_recv[2];
+
+ if(memory_type_capacity == MTC_W25Q128_BV)
+ {
+ FLASH_TRACE("W25Q128BV detection\r\n");
+ spi_flash_device.geometry.sector_count = 4096;
+ }
+ else if(memory_type_capacity == MTC_W25Q64_BV_CV)
+ {
+ FLASH_TRACE("W25Q64BV or W25Q64CV detection\r\n");
+ spi_flash_device.geometry.sector_count = 2048;
+ }
+ else if(memory_type_capacity == MTC_W25Q64_DW)
+ {
+ FLASH_TRACE("W25Q64DW detection\r\n");
+ spi_flash_device.geometry.sector_count = 2048;
+ }
+ else if(memory_type_capacity == MTC_W25Q32_BV)
+ {
+ FLASH_TRACE("W25Q32BV detection\r\n");
+ spi_flash_device.geometry.sector_count = 1024;
+ }
+ else if(memory_type_capacity == MTC_W25Q32_DW)
+ {
+ FLASH_TRACE("W25Q32DW detection\r\n");
+ spi_flash_device.geometry.sector_count = 1024;
+ }
+ else if(memory_type_capacity == MTC_W25Q16_BV_CL_CV)
+ {
+ FLASH_TRACE("W25Q16BV or W25Q16CL or W25Q16CV detection\r\n");
+ spi_flash_device.geometry.sector_count = 512;
+ }
+ else if(memory_type_capacity == MTC_W25Q16_DW)
+ {
+ FLASH_TRACE("W25Q16DW detection\r\n");
+ spi_flash_device.geometry.sector_count = 512;
+ }
+ else
+ {
+ FLASH_TRACE("Memory Capacity error!\r\n");
+ return -RT_ENOSYS;
+ }
+ }
+
+ /* register device */
+ spi_flash_device.flash_device.type = RT_Device_Class_Block;
+ spi_flash_device.flash_device.init = w25qxx_flash_init;
+ spi_flash_device.flash_device.open = w25qxx_flash_open;
+ spi_flash_device.flash_device.close = w25qxx_flash_close;
+ spi_flash_device.flash_device.read = w25qxx_flash_read;
+ spi_flash_device.flash_device.write = w25qxx_flash_write;
+ spi_flash_device.flash_device.control = w25qxx_flash_control;
+ /* no private */
+ spi_flash_device.flash_device.user_data = RT_NULL;
+
+ rt_device_register(&spi_flash_device.flash_device, flash_device_name,
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+ return RT_EOK;
+}
diff --git a/components/drivers/spi/spi_flash_w25qxx.h b/components/drivers/spi/spi_flash_w25qxx.h
new file mode 100644
index 0000000000..ebab35da33
--- /dev/null
+++ b/components/drivers/spi/spi_flash_w25qxx.h
@@ -0,0 +1,34 @@
+/*
+ * File : spi_flash_w25qxx.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ * 2012-08-23 aozima add flash lock.
+ */
+
+#ifndef SPI_FLASH_W25QXX_H_INCLUDED
+#define SPI_FLASH_W25QXX_H_INCLUDED
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+struct spi_flash_device
+{
+ struct rt_device flash_device;
+ struct rt_device_blk_geometry geometry;
+ struct rt_spi_device * rt_spi_device;
+ struct rt_mutex lock;
+};
+
+extern rt_err_t w25qxx_init(const char * flash_device_name,
+ const char * spi_device_name);
+
+
+#endif // SPI_FLASH_W25QXX_H_INCLUDED
diff --git a/components/drivers/spi/spi_wifi_rw009.c b/components/drivers/spi/spi_wifi_rw009.c
new file mode 100644
index 0000000000..9f5601bf26
--- /dev/null
+++ b/components/drivers/spi/spi_wifi_rw009.c
@@ -0,0 +1,847 @@
+/*
+ * File : spi_wifi_rw009.c
+ * This file is part of RT-Thread RTOS
+ * Copyright by Shanghai Real-Thread Electronic Technology Co.,Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2014-07-31 aozima the first version
+ * 2014-09-18 aozima update command & response.
+ */
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+#include <netif/ethernetif.h>
+#include <netif/etharp.h>
+#include <lwip/icmp.h>
+#include "lwipopts.h"
+
+#define WIFI_DEBUG_ON
+// #define ETH_RX_DUMP
+// #define ETH_TX_DUMP
+
+#ifdef WIFI_DEBUG_ON
+#define WIFI_DEBUG rt_kprintf("[RW009] ");rt_kprintf
+//#define SPI_DEBUG rt_kprintf("[SPI] ");rt_kprintf
+#define SPI_DEBUG(...)
+#else
+#define WIFI_DEBUG(...)
+#define SPI_DEBUG(...)
+#endif /* #ifdef WIFI_DEBUG_ON */
+
+/********************************* RW009 **************************************/
+#include "spi_wifi_rw009.h"
+
+/* tools */
+#define node_entry(node, type, member) \
+ ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member)))
+#define member_offset(type, member) \
+ ((unsigned long)(&((type *)0)->member))
+
+#define MAX_SPI_PACKET_SIZE (member_offset(struct spi_data_packet, buffer) + SPI_MAX_DATA_LEN)
+#define MAX_SPI_BUFFER_SIZE (sizeof(struct spi_response) + MAX_SPI_PACKET_SIZE)
+#define MAX_ADDR_LEN 6
+
+struct rw009_wifi
+{
+ /* inherit from ethernet device */
+ struct eth_device parent;
+
+ struct rt_spi_device *rt_spi_device;
+
+ /* interface address info. */
+ rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
+ rt_uint8_t active;
+
+ struct rt_mempool spi_tx_mp;
+ struct rt_mempool spi_rx_mp;
+
+ struct rt_mailbox spi_tx_mb;
+ struct rt_mailbox eth_rx_mb;
+
+ int spi_tx_mb_pool[SPI_TX_POOL_SIZE + 1];
+ int eth_rx_mb_pool[SPI_RX_POOL_SIZE + 1];
+
+ int rw009_cmd_mb_pool[3];
+ struct rt_mailbox rw009_cmd_mb;
+ uint32_t last_cmd;
+
+ ALIGN(4)
+ rt_uint8_t spi_tx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE];
+ ALIGN(4)
+ rt_uint8_t spi_rx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_RX_POOL_SIZE];
+
+ ALIGN(4)
+ uint8_t spi_hw_rx_buffer[MAX_SPI_BUFFER_SIZE];
+
+ /* status for RW009 */
+ rw009_ap_info ap_info; /* AP info for conn. */
+ rw009_ap_info *ap_scan; /* AP list for SCAN. */
+ uint32_t ap_scan_count;
+};
+static struct rw009_wifi rw009_wifi_device;
+static struct rt_event spi_wifi_data_event;
+
+static void resp_handler(struct rw009_wifi *wifi_device, struct rw009_resp *resp)
+{
+ struct rw009_resp *resp_return = RT_NULL;
+
+ switch (resp->cmd)
+ {
+ case RW009_CMD_INIT:
+ WIFI_DEBUG("resp_handler RW009_CMD_INIT\n");
+ resp_return = (struct rw009_resp *)rt_malloc(member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_init)); //TODO:
+ if(resp_return == RT_NULL) break;
+ memcpy(resp_return, resp, member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_init));
+
+ WIFI_DEBUG("sn:%-*.*s\n", sizeof(resp->resp.init.sn), sizeof(resp->resp.init.sn), resp->resp.init.sn);
+ WIFI_DEBUG("version:%-*.*s\n", sizeof(resp->resp.init.version), sizeof(resp->resp.init.version), resp->resp.init.version);
+
+ rt_memcpy(wifi_device->dev_addr, resp->resp.init.mac, 6);
+ break;
+
+ case RW009_CMD_SCAN:
+ if( resp->len == sizeof(rw009_ap_info) )
+ {
+ rw009_ap_info *ap_scan = rt_realloc(wifi_device->ap_scan, sizeof(rw009_ap_info) * (wifi_device->ap_scan_count + 1) );
+ if(ap_scan != RT_NULL)
+ {
+ memcpy( &ap_scan[wifi_device->ap_scan_count], &resp->resp.ap_info, sizeof(rw009_ap_info) );
+
+ //dump
+ if(1)
+ {
+#ifdef WIFI_DEBUG_ON
+ rw009_ap_info *ap_info = &resp->resp.ap_info;
+ WIFI_DEBUG("SCAN SSID:%-32.32s\n", ap_info->ssid);
+ WIFI_DEBUG("SCAN BSSID:%02X-%02X-%02X-%02X-%02X-%02X\n",
+ ap_info->bssid[0],
+ ap_info->bssid[1],
+ ap_info->bssid[2],
+ ap_info->bssid[3],
+ ap_info->bssid[4],
+ ap_info->bssid[5]);
+ WIFI_DEBUG("SCAN rssi:%ddBm\n", ap_info->rssi);
+ WIFI_DEBUG("SCAN rate:%dMbps\n", ap_info->max_data_rate/1000);
+ WIFI_DEBUG("SCAN channel:%d\n", ap_info->channel);
+ WIFI_DEBUG("SCAN security:%08X\n\n", ap_info->security);
+#endif /* WIFI_DEBUG_ON */
+ }
+
+ wifi_device->ap_scan_count++;
+ wifi_device->ap_scan = ap_scan;
+ }
+
+ return; /* wait for next ap */
+ }
+ break;
+ case RW009_CMD_JOIN:
+ case RW009_CMD_EASY_JOIN:
+ WIFI_DEBUG("resp_handler RW009_CMD_EASY_JOIN\n");
+ resp_return = (struct rw009_resp *)rt_malloc(member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_join)); //TODO:
+ if(resp_return == RT_NULL) break;
+ memcpy(resp_return, resp, member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_join));
+
+ if( resp->result == 0 )
+ {
+ memcpy(&wifi_device->ap_info, &resp_return->resp.ap_info, sizeof(rw009_resp_join));
+ wifi_device->active = 1;
+ eth_device_linkchange(&wifi_device->parent, RT_TRUE);
+ }
+ else
+ {
+ WIFI_DEBUG("RW009_CMD_EASY_JOIN result: %d\n", resp->result );
+ }
+
+ //dupm
+ if(1)
+ {
+#ifdef WIFI_DEBUG_ON
+ rw009_ap_info *ap_info = &resp->resp.ap_info;
+ WIFI_DEBUG("JOIN SSID:%-32.32s\n", ap_info->ssid);
+ WIFI_DEBUG("JOIN BSSID:%02X-%02X-%02X-%02X-%02X-%02X\n",
+ ap_info->bssid[0],
+ ap_info->bssid[1],
+ ap_info->bssid[2],
+ ap_info->bssid[3],
+ ap_info->bssid[4],
+ ap_info->bssid[5]);
+ WIFI_DEBUG("JOIN rssi:%ddBm\n", ap_info->rssi);
+ WIFI_DEBUG("JOIN rate:%dMbps\n", ap_info->max_data_rate/1000);
+ WIFI_DEBUG("JOIN channel:%d\n", ap_info->channel);
+ WIFI_DEBUG("JOIN security:%08X\n\n", ap_info->security);
+#endif /* WIFI_DEBUG_ON */
+ }
+ break;
+
+ case RW009_CMD_RSSI:
+ // TODO: client RSSI.
+ {
+ rw009_ap_info *ap_info = &resp->resp.ap_info;
+ wifi_device->ap_info.rssi = ap_info->rssi;
+ WIFI_DEBUG("current RSSI: %d\n", wifi_device->ap_info.rssi);
+ }
+ break;
+
+ case RW009_CMD_SOFTAP:
+ {
+ if( resp->result == 0 )
+ {
+ ;
+ wifi_device->active = 1;
+ eth_device_linkchange(&wifi_device->parent, RT_TRUE);
+ }
+ else
+ {
+ WIFI_DEBUG("RW009_CMD_EASY_JOIN result: %d\n", resp->result );
+ }
+
+ }
+ break;
+
+ default:
+ WIFI_DEBUG("resp_handler %d\n", resp->cmd);
+ break;
+ }
+
+
+ if(resp->cmd == wifi_device->last_cmd)
+ {
+ rt_mb_send(&wifi_device->rw009_cmd_mb, (rt_uint32_t)resp_return);
+ return;
+ }
+ else
+ {
+ rt_free(resp_return);
+ }
+}
+
+static rt_err_t rw009_cmd(struct rw009_wifi *wifi_device, uint32_t cmd, void *args)
+{
+ rt_err_t result = RT_EOK;
+ rt_int32_t timeout = RW009_CMD_TIMEOUT;
+
+ struct spi_data_packet *data_packet;
+ struct rw009_cmd *wifi_cmd = RT_NULL;
+ struct rw009_resp *resp = RT_NULL;
+
+ wifi_device->last_cmd = cmd;
+
+ data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+ wifi_cmd = (struct rw009_cmd *)data_packet->buffer;
+
+ wifi_cmd->cmd = cmd;
+ wifi_cmd->len = 0;
+
+ if( cmd == RW009_CMD_INIT )
+ {
+ wifi_cmd->len = sizeof(rw009_cmd_init);
+ }
+ else if( cmd == RW009_CMD_SCAN )
+ {
+ wifi_cmd->len = 0;
+ timeout += RT_TICK_PER_SECOND*10;
+
+ if(wifi_device->ap_scan)
+ {
+ rt_free(wifi_device->ap_scan);
+ wifi_device->ap_scan = RT_NULL;
+ wifi_device->ap_scan_count = 0;
+ }
+ }
+ else if( cmd == RW009_CMD_JOIN )
+ {
+ wifi_cmd->len = sizeof(rw009_cmd_join);
+ }
+ else if( cmd == RW009_CMD_EASY_JOIN )
+ {
+ wifi_cmd->len = sizeof(rw009_cmd_easy_join);
+ timeout += RT_TICK_PER_SECOND*5;
+ }
+ else if( cmd == RW009_CMD_RSSI )
+ {
+ wifi_cmd->len = sizeof(rw009_cmd_rssi);
+ }
+ else if( cmd == RW009_CMD_SOFTAP )
+ {
+ wifi_cmd->len = sizeof(rw009_cmd_softap);
+ }
+ else
+ {
+ WIFI_DEBUG("unkown RW009 CMD %d\n", cmd);
+ result = -RT_ENOSYS;
+ rt_mp_free(data_packet);
+ data_packet = RT_NULL;
+ }
+
+ if(data_packet == RT_NULL)
+ {
+ goto _exit;
+ }
+
+ if(wifi_cmd->len)
+ memcpy(&wifi_cmd->params, args, wifi_cmd->len);
+
+ data_packet->data_type = data_type_cmd;
+ data_packet->data_len = member_offset(struct rw009_cmd, params) + wifi_cmd->len;
+
+ rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+ rt_event_send(&spi_wifi_data_event, 1);
+
+ result = rt_mb_recv(&wifi_device->rw009_cmd_mb,
+ (rt_uint32_t *)&resp,
+ timeout);
+
+ if ( result != RT_EOK )
+ {
+ WIFI_DEBUG("CMD %d error, resultL %d\n", cmd, result );
+ }
+
+ if(resp != RT_NULL)
+ result = resp->result;
+
+_exit:
+ wifi_device->last_cmd = 0;
+ if(resp) rt_free(resp);
+ return result;
+}
+
+static rt_err_t spi_wifi_transfer(struct rw009_wifi *dev)
+{
+ struct pbuf *p = RT_NULL;
+ struct spi_cmd_request cmd;
+ struct spi_response resp;
+
+ rt_err_t result;
+ const struct spi_data_packet *data_packet = RT_NULL;
+
+ struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
+ struct rt_spi_device *rt_spi_device = wifi_device->rt_spi_device;
+
+ spi_wifi_int_cmd(0);
+ while (spi_wifi_is_busy());
+ SPI_DEBUG("sequence start!\n");
+
+ memset(&cmd, 0, sizeof(struct spi_cmd_request));
+ cmd.magic1 = CMD_MAGIC1;
+ cmd.magic2 = CMD_MAGIC2;
+
+ cmd.flag |= CMD_FLAG_MRDY;
+
+ result = rt_mb_recv(&wifi_device->spi_tx_mb,
+ (rt_uint32_t *)&data_packet,
+ 0);
+ if ((result == RT_EOK) && (data_packet != RT_NULL) && (data_packet->data_len > 0))
+ {
+ cmd.M2S_len = data_packet->data_len + member_offset(struct spi_data_packet, buffer);
+ //SPI_DEBUG("cmd.M2S_len = %d\n", cmd.M2S_len);
+ }
+
+ rt_spi_send(rt_spi_device, &cmd, sizeof(cmd));
+ while (spi_wifi_is_busy());
+
+ {
+ struct rt_spi_message message;
+ uint32_t max_data_len = 0;
+
+ /* setup message */
+ message.send_buf = RT_NULL;
+ message.recv_buf = &resp;
+ message.length = sizeof(resp);
+ message.cs_take = 1;
+ message.cs_release = 0;
+
+ rt_spi_take_bus(rt_spi_device);
+
+ /* transfer message */
+ rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
+
+ if ((resp.magic1 != RESP_MAGIC1) || (resp.magic2 != RESP_MAGIC2))
+ {
+ SPI_DEBUG("bad resp magic, abort!\n");
+ goto _bad_resp_magic;
+ }
+
+ if (resp.flag & RESP_FLAG_SRDY)
+ {
+ SPI_DEBUG("RESP_FLAG_SRDY\n");
+ max_data_len = cmd.M2S_len;
+ }
+
+ if (resp.S2M_len)
+ {
+ SPI_DEBUG("resp.S2M_len: %d\n", resp.S2M_len);
+ if (resp.S2M_len > MAX_SPI_PACKET_SIZE)
+ {
+ SPI_DEBUG("resp.S2M_len %d > %d(MAX_SPI_PACKET_SIZE), drop!\n", resp.S2M_len, MAX_SPI_PACKET_SIZE);
+ resp.S2M_len = 0;//drop
+ }
+
+ if (resp.S2M_len > max_data_len)
+ max_data_len = resp.S2M_len;
+ }
+
+ if (max_data_len == 0)
+ {
+ SPI_DEBUG("no rx or tx data!\n");
+ }
+
+ //SPI_DEBUG("max_data_len = %d\n", max_data_len);
+
+_bad_resp_magic:
+ /* setup message */
+ message.send_buf = data_packet;//&tx_buffer;
+ message.recv_buf = wifi_device->spi_hw_rx_buffer;//&rx_buffer;
+ message.length = max_data_len;
+ message.cs_take = 0;
+ message.cs_release = 1;
+
+ /* transfer message */
+ rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
+
+ rt_spi_release_bus(rt_spi_device);
+
+ if (cmd.M2S_len && (resp.flag & RESP_FLAG_SRDY))
+ {
+ rt_mp_free((void *)data_packet);
+ }
+
+ if ((resp.S2M_len) && (resp.S2M_len <= MAX_SPI_PACKET_SIZE))
+ {
+ data_packet = (struct spi_data_packet *)wifi_device->spi_hw_rx_buffer;
+ if (data_packet->data_type == data_type_eth_data)
+ {
+
+ if (wifi_device->active)
+ {
+ p = pbuf_alloc(PBUF_LINK, data_packet->data_len, PBUF_RAM);
+ pbuf_take(p, (rt_uint8_t *)data_packet->buffer, data_packet->data_len);
+
+ rt_mb_send(&wifi_device->eth_rx_mb, (rt_uint32_t)p);
+ eth_device_ready((struct eth_device *)dev);
+ }
+ else
+ {
+ SPI_DEBUG("!active, RX drop.\n");
+ }
+ }
+ else if (data_packet->data_type == data_type_resp)
+ {
+ SPI_DEBUG("data_type_resp\n");
+ resp_handler(dev, (struct rw009_resp *)data_packet->buffer);
+ }
+ else
+ {
+ SPI_DEBUG("data_type: %d, %dbyte\n",
+ data_packet->data_type,
+ data_packet->data_len);
+ }
+ }
+ }
+ spi_wifi_int_cmd(1);
+
+ SPI_DEBUG("sequence finish!\n\n");
+
+ if ((cmd.M2S_len == 0) && (resp.S2M_len == 0))
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+#if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
+static void packet_dump(const char *msg, const struct pbuf *p)
+{
+ const struct pbuf* q;
+ rt_uint32_t i,j;
+ rt_uint8_t *ptr = p->payload;
+
+ rt_kprintf("%s %d byte\n", msg, p->tot_len);
+
+ i=0;
+ for(q=p; q != RT_NULL; q= q->next)
+ {
+ ptr = q->payload;
+
+ for(j=0; j<q->len; j++)
+ {
+ if( (i%8) == 0 )
+ {
+ rt_kprintf(" ");
+ }
+ if( (i%16) == 0 )
+ {
+ rt_kprintf("\r\n");
+ }
+ rt_kprintf("%02x ",*ptr);
+
+ i++;
+ ptr++;
+ }
+ }
+ rt_kprintf("\n\n");
+}
+#endif /* dump */
+
+/********************************* RT-Thread Ethernet interface begin **************************************/
+static rt_err_t rw009_wifi_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t rw009_wifi_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ return RT_EOK;
+}
+
+static rt_err_t rw009_wifi_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_size_t rw009_wifi_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+static rt_size_t rw009_wifi_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+static rt_err_t rw009_wifi_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
+ rt_err_t result = RT_EOK;
+
+ if (cmd == NIOCTL_GADDR)
+ {
+ memcpy(args, wifi_device->dev_addr, 6);
+ }
+ else
+ {
+ result = rw009_cmd(wifi_device, cmd, args);
+ }
+
+ return result;
+}
+
+/* transmit packet. */
+rt_err_t rw009_wifi_tx(rt_device_t dev, struct pbuf *p)
+{
+ rt_err_t result = RT_EOK;
+ struct spi_data_packet *data_packet;
+ struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
+
+ if (!wifi_device->active)
+ {
+ WIFI_DEBUG("!active, TX drop!\n");
+ return RT_EOK;
+ }
+
+ /* get free tx buffer */
+ data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+ if (data_packet != RT_NULL)
+ {
+ data_packet->data_type = data_type_eth_data;
+ data_packet->data_len = p->tot_len;
+
+ pbuf_copy_partial(p, data_packet->buffer, data_packet->data_len, 0);
+
+ rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+ rt_event_send(&spi_wifi_data_event, 1);
+ }
+ else
+ return -RT_ERROR;
+
+#ifdef ETH_TX_DUMP
+ packet_dump("TX dump", p);
+#endif /* ETH_TX_DUMP */
+
+ /* Return SUCCESS */
+ return result;
+}
+
+/* reception packet. */
+struct pbuf *rw009_wifi_rx(rt_device_t dev)
+{
+ struct pbuf *p = RT_NULL;
+ struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
+
+ if (rt_mb_recv(&wifi_device->eth_rx_mb, (rt_uint32_t *)&p, 0) != RT_EOK)
+ {
+ return RT_NULL;
+ }
+
+#ifdef ETH_RX_DUMP
+ if(p)
+ packet_dump("RX dump", p);
+#endif /* ETH_RX_DUMP */
+
+ return p;
+}
+/********************************* RT-Thread Ethernet interface end **************************************/
+
+static void spi_wifi_data_thread_entry(void *parameter)
+{
+ rt_uint32_t e;
+ rt_err_t result;
+
+ while (1)
+ {
+ /* receive first event */
+ if (rt_event_recv(&spi_wifi_data_event,
+ 1,
+ RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
+ RT_WAITING_FOREVER,
+ &e) != RT_EOK)
+ {
+ continue;
+ }
+
+ result = spi_wifi_transfer(&rw009_wifi_device);
+
+ if (result == RT_EOK)
+ {
+ rt_event_send(&spi_wifi_data_event, 1);
+ }
+ }
+}
+
+rt_err_t rt_hw_wifi_init(const char *spi_device_name, wifi_mode_t mode)
+{
+ /* align and struct size check. */
+ RT_ASSERT( (SPI_MAX_DATA_LEN & 0x03) == 0);
+ RT_ASSERT( sizeof(struct rw009_resp) <= SPI_MAX_DATA_LEN);
+
+ memset(&rw009_wifi_device, 0, sizeof(struct rw009_wifi));
+
+ rw009_wifi_device.rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+
+ if (rw009_wifi_device.rt_spi_device == RT_NULL)
+ {
+ SPI_DEBUG("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0. */
+ cfg.max_hz = 15 * 1000000; /* 10M */
+ rt_spi_configure(rw009_wifi_device.rt_spi_device, &cfg);
+ }
+
+ rw009_wifi_device.parent.parent.init = rw009_wifi_init;
+ rw009_wifi_device.parent.parent.open = rw009_wifi_open;
+ rw009_wifi_device.parent.parent.close = rw009_wifi_close;
+ rw009_wifi_device.parent.parent.read = rw009_wifi_read;
+ rw009_wifi_device.parent.parent.write = rw009_wifi_write;
+ rw009_wifi_device.parent.parent.control = rw009_wifi_control;
+ rw009_wifi_device.parent.parent.user_data = RT_NULL;
+
+ rw009_wifi_device.parent.eth_rx = rw009_wifi_rx;
+ rw009_wifi_device.parent.eth_tx = rw009_wifi_tx;
+
+ rt_mp_init(&rw009_wifi_device.spi_tx_mp,
+ "spi_tx",
+ &rw009_wifi_device.spi_tx_mempool[0],
+ sizeof(rw009_wifi_device.spi_tx_mempool),
+ sizeof(struct spi_data_packet));
+
+ rt_mp_init(&rw009_wifi_device.spi_rx_mp,
+ "spi_rx",
+ &rw009_wifi_device.spi_rx_mempool[0],
+ sizeof(rw009_wifi_device.spi_rx_mempool),
+ sizeof(struct spi_data_packet));
+
+ rt_mb_init(&rw009_wifi_device.spi_tx_mb,
+ "spi_tx",
+ &rw009_wifi_device.spi_tx_mb_pool[0],
+ SPI_TX_POOL_SIZE,
+ RT_IPC_FLAG_PRIO);
+
+ rt_mb_init(&rw009_wifi_device.eth_rx_mb,
+ "eth_rx",
+ &rw009_wifi_device.eth_rx_mb_pool[0],
+ SPI_TX_POOL_SIZE,
+ RT_IPC_FLAG_PRIO);
+
+ rt_mb_init(&rw009_wifi_device.rw009_cmd_mb,
+ "wifi_cmd",
+ &rw009_wifi_device.rw009_cmd_mb_pool[0],
+ sizeof(rw009_wifi_device.rw009_cmd_mb_pool) / 4,
+ RT_IPC_FLAG_PRIO);
+ rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO);
+
+ spi_wifi_hw_init();
+
+ {
+ rt_thread_t tid;
+
+
+ tid = rt_thread_create("wifi",
+ spi_wifi_data_thread_entry,
+ RT_NULL,
+ 2048,
+ RT_THREAD_PRIORITY_MAX - 2,
+ 20);
+
+ if (tid != RT_NULL)
+ rt_thread_startup(tid);
+ }
+
+ /* init: get mac address */
+ {
+ rw009_cmd_init init;
+ init.mode = mode;
+ WIFI_DEBUG("wifi_control RW009_CMD_INIT\n");
+ rw009_wifi_control((rt_device_t)&rw009_wifi_device,
+ RW009_CMD_INIT,
+ (void *)&init); // 0: firmware, 1: STA, 2:AP
+
+ }
+
+ /* register eth device */
+ eth_device_init(&(rw009_wifi_device.parent), "w0");
+ eth_device_linkchange(&rw009_wifi_device.parent, RT_FALSE);
+
+ return RT_EOK;
+}
+
+void spi_wifi_isr(int vector)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ SPI_DEBUG("spi_wifi_isr\n");
+ rt_event_send(&spi_wifi_data_event, 1);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+/********************************* RW009 tools **************************************/
+rt_err_t rw009_join(const char * SSID, const char * passwd)
+{
+ rt_err_t result;
+ rt_device_t wifi_device;
+ rw009_cmd_easy_join easy_join;
+
+ wifi_device = rt_device_find("w0");
+ if(wifi_device == RT_NULL)
+ return -RT_ENOSYS;
+
+ strncpy( easy_join.ssid, SSID, sizeof(easy_join.ssid) );
+ strncpy( easy_join.passwd, passwd, sizeof(easy_join.passwd) );
+
+ result = rt_device_control(wifi_device,
+ RW009_CMD_EASY_JOIN,
+ (void *)&easy_join);
+
+ return result;
+}
+
+rt_err_t rw009_softap(const char * SSID, const char * passwd,uint32_t security,uint32_t channel)
+{
+ rt_err_t result;
+ rt_device_t wifi_device;
+ rw009_cmd_softap softap;
+
+ wifi_device = rt_device_find("w0");
+ if(wifi_device == RT_NULL)
+ return -RT_ENOSYS;
+
+ strncpy( softap.ssid, SSID, sizeof(softap.ssid) );
+ strncpy( softap.passwd, passwd, sizeof(softap.passwd) );
+
+ softap.security = security;
+ softap.channel = channel;
+ result = rt_device_control(wifi_device,
+ RW009_CMD_SOFTAP,
+ (void *)&softap);
+
+ return result;
+}
+
+int32_t rw009_rssi(void)
+{
+ rt_err_t result;
+ struct rw009_wifi * wifi_device;
+
+ wifi_device = (struct rw009_wifi *)rt_device_find("w0");
+
+ if(wifi_device == RT_NULL)
+ return 0;
+
+ if(wifi_device->active == 0)
+ return 0;
+
+ // SCAN
+ result = rt_device_control((rt_device_t)wifi_device,
+ RW009_CMD_RSSI,
+ RT_NULL);
+
+ if(result == RT_EOK)
+ {
+ return wifi_device->ap_info.rssi;
+ }
+
+ return 0;
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+
+static rt_err_t rw009_scan(void)
+{
+ rt_err_t result;
+ struct rw009_wifi * wifi_device;
+
+ wifi_device = (struct rw009_wifi *)rt_device_find("w0");
+
+ rt_kprintf("\nCMD RW009_CMD_SCAN \n");
+ result = rt_device_control((rt_device_t)wifi_device,
+ RW009_CMD_SCAN,
+ RT_NULL);
+
+ rt_kprintf("CMD RW009_CMD_SCAN result:%d\n", result);
+
+ if(result == RT_EOK)
+ {
+ uint32_t i;
+ rw009_ap_info *ap_info;
+
+ for(i=0; i<wifi_device->ap_scan_count; i++)
+ {
+ ap_info = &wifi_device->ap_scan[i];
+ rt_kprintf("AP #%02d SSID: %-32.32s\n", i, ap_info->ssid );
+ }
+ }
+
+ return result;
+}
+FINSH_FUNCTION_EXPORT(rw009_scan, SACN and list AP.);
+FINSH_FUNCTION_EXPORT(rw009_join, RW009 join to AP.);
+FINSH_FUNCTION_EXPORT(rw009_rssi, get RW009 current AP rssi.);
+
+#endif // RT_USING_FINSH
diff --git a/components/drivers/spi/spi_wifi_rw009.h b/components/drivers/spi/spi_wifi_rw009.h
new file mode 100644
index 0000000000..4b684b9b24
--- /dev/null
+++ b/components/drivers/spi/spi_wifi_rw009.h
@@ -0,0 +1,226 @@
+/*
+ * File : spi_wifi_rw009.h
+ * This file is part of RT-Thread RTOS
+ * Copyright by Shanghai Real-Thread Electronic Technology Co.,Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2014-07-31 aozima the first version
+ * 2014-09-18 aozima update command & response.
+ */
+
+#ifndef SPI_WIFI_H_INCLUDED
+#define SPI_WIFI_H_INCLUDED
+
+#include <stdint.h>
+
+// little-endian
+struct spi_cmd_request
+{
+ uint32_t flag;
+ uint32_t M2S_len; // master to slave data len.
+ uint32_t magic1;
+ uint32_t magic2;
+};
+
+#define CMD_MAGIC1 (0x67452301)
+#define CMD_MAGIC2 (0xEFCDAB89)
+
+#define CMD_FLAG_MRDY (0x01)
+
+// little-endian
+struct spi_response
+{
+ uint32_t flag;
+ uint32_t S2M_len; // slave to master data len.
+ uint32_t magic1;
+ uint32_t magic2;
+};
+
+#define RESP_FLAG_SRDY (0x01)
+#define RESP_MAGIC1 (0x98BADCFE)
+#define RESP_MAGIC2 (0x10325476)
+
+/* spi slave configure. */
+#define SPI_MAX_DATA_LEN 1520
+#define SPI_TX_POOL_SIZE 2
+#define SPI_RX_POOL_SIZE 2
+
+typedef enum
+{
+ data_type_eth_data = 0,
+ data_type_cmd,
+ data_type_resp,
+ data_type_status,
+}
+app_data_type_typedef;
+
+struct spi_data_packet
+{
+ uint32_t data_len;
+ uint32_t data_type;
+ char buffer[SPI_MAX_DATA_LEN];
+};
+
+/********************************* RW009 **************************************/
+
+/* option */
+#define RW009_CMD_TIMEOUT (RT_TICK_PER_SECOND*3)
+#define SSID_NAME_LENGTH_MAX (32)
+#define PASSWORD_LENGTH_MAX (64)
+
+typedef enum
+{
+ MODE_STATION=0,
+ MODE_SOFTAP=1,
+} wifi_mode_t;
+
+typedef struct _rw009_ap_info
+{
+ char ssid[SSID_NAME_LENGTH_MAX];
+ uint8_t bssid[8]; // 6byte + 2byte PAD.
+ int rssi; /* Receive Signal Strength Indication in dBm. */
+ uint32_t max_data_rate; /* Maximum data rate in kilobits/s */
+ uint32_t security; /* Security type */
+ uint32_t channel; /* Radio channel that the AP beacon was received on */
+} rw009_ap_info;
+
+typedef struct _rw009_cmd_init
+{
+ uint32_t mode;
+} rw009_cmd_init;
+
+typedef struct _rw009_resp_init
+{
+ uint8_t mac[8]; // 6byte + 2byte PAD.
+ uint8_t sn[24]; // serial.
+ char version[16]; // firmware version.
+} rw009_resp_init;
+
+typedef struct _rw009_cmd_easy_join
+{
+ char ssid[SSID_NAME_LENGTH_MAX];
+ char passwd[PASSWORD_LENGTH_MAX];
+} rw009_cmd_easy_join;
+
+typedef struct _rw009_cmd_join
+{
+ uint8_t bssid[8]; // 6byte + 2byte PAD.
+ char passwd[PASSWORD_LENGTH_MAX];
+} rw009_cmd_join;
+
+typedef struct _rw009_cmd_rssi
+{
+ uint8_t bssid[8]; // 6byte + 2byte PAD.
+} rw009_cmd_rssi;
+
+typedef struct _rw009_cmd_softap
+{
+ char ssid[SSID_NAME_LENGTH_MAX];
+ char passwd[PASSWORD_LENGTH_MAX];
+
+ uint32_t security; /* Security type. */
+ uint32_t channel; /* Radio channel that the AP beacon was received on */
+} rw009_cmd_softap;
+
+typedef struct _rw009_resp_join
+{
+ rw009_ap_info ap_info;
+} rw009_resp_join;
+
+struct rw009_cmd
+{
+ uint32_t cmd;
+ uint32_t len;
+
+ /** command body */
+ union
+ {
+ rw009_cmd_init init;
+ rw009_cmd_easy_join easy_join;
+ rw009_cmd_join join;
+ rw009_cmd_rssi rssi;
+ rw009_cmd_softap softap;
+ } params;
+};
+
+struct rw009_resp
+{
+ uint32_t cmd;
+ uint32_t len;
+
+ int32_t result; // result for CMD.
+
+ /** resp Body */
+ union
+ {
+ rw009_resp_init init;
+ rw009_ap_info ap_info;
+ } resp;
+};
+
+#define RW009_CMD_INIT 128
+#define RW009_CMD_SCAN 129
+#define RW009_CMD_JOIN 130
+#define RW009_CMD_EASY_JOIN 131
+#define RW009_CMD_RSSI 132
+#define RW009_CMD_SOFTAP 133
+
+/** cond !ADDTHIS*/
+#define SHARED_ENABLED 0x00008000
+#define WPA_SECURITY 0x00200000
+#define WPA2_SECURITY 0x00400000
+#define WPS_ENABLED 0x10000000
+#define WEP_ENABLED 0x0001
+#define TKIP_ENABLED 0x0002
+#define AES_ENABLED 0x0004
+#define WSEC_SWFLAG 0x0008
+/** endcond */
+/**
+ * Enumeration of Wi-Fi security modes
+ */
+typedef enum
+{
+ SECURITY_OPEN = 0, /**< Open security */
+ SECURITY_WEP_PSK = WEP_ENABLED, /**< WEP Security with open authentication */
+ SECURITY_WEP_SHARED = ( WEP_ENABLED | SHARED_ENABLED ), /**< WEP Security with shared authentication */
+ SECURITY_WPA_TKIP_PSK = ( WPA_SECURITY | TKIP_ENABLED ), /**< WPA Security with TKIP */
+ SECURITY_WPA_AES_PSK = ( WPA_SECURITY | AES_ENABLED ), /**< WPA Security with AES */
+ SECURITY_WPA2_AES_PSK = ( WPA2_SECURITY | AES_ENABLED ), /**< WPA2 Security with AES */
+ SECURITY_WPA2_TKIP_PSK = ( WPA2_SECURITY | TKIP_ENABLED ), /**< WPA2 Security with TKIP */
+ SECURITY_WPA2_MIXED_PSK = ( WPA2_SECURITY | AES_ENABLED | TKIP_ENABLED ), /**< WPA2 Security with AES & TKIP */
+
+ SECURITY_WPS_OPEN = WPS_ENABLED, /**< WPS with open security */
+ SECURITY_WPS_SECURE = (WPS_ENABLED | AES_ENABLED), /**< WPS with AES security */
+
+ SECURITY_UNKNOWN = -1, /**< May be returned by scan function if security is unknown. Do not pass this to the join function! */
+
+ SECURITY_FORCE_32_BIT = 0x7fffffff /**< Exists only to force wiced_security_t type to 32 bits */
+} security_t;
+
+/* porting */
+extern void spi_wifi_hw_init(void);
+extern void spi_wifi_int_cmd(rt_bool_t cmd);
+extern rt_bool_t spi_wifi_is_busy(void);
+
+/* export API. */
+extern rt_err_t rt_hw_wifi_init(const char *spi_device_name,wifi_mode_t mode);
+extern int32_t rw009_rssi(void);
+extern rt_err_t rw009_join(const char * SSID, const char * passwd);
+extern rt_err_t rw009_softap(const char * SSID, const char * passwd,uint32_t security,uint32_t channel);
+
+#endif // SPI_WIFI_H_INCLUDED
diff --git a/components/drivers/src/workqueue.c b/components/drivers/src/workqueue.c
index 52f6002595..d9062e6cdb 100644
--- a/components/drivers/src/workqueue.c
+++ b/components/drivers/src/workqueue.c
@@ -33,7 +33,7 @@ static void _workqueue_thread_entry(void* parameter)
struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority)
{
struct rt_workqueue *queue = RT_NULL;
-
+
queue = (struct rt_workqueue*)RT_KERNEL_MALLOC(sizeof(struct rt_workqueue));
if (queue != RT_NULL)
{