代码拉取完成,页面将自动刷新
/*
* /linux-3.0.8/drivers/spi/gt210_nrf2401.c
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/compat.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/list.h>
#include <mach/irqs.h>
#include <mach/regs-gpio.h>
#include <asm/uaccess.h>
#include "gt210_nrf2401.h"
#include "nrf2401_test.h"
static DECLARE_BITMAP(minors, N_SPI_MINORS);
static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);
static struct class *gt210_nrf2401_class = NULL;
static const struct file_operations gt210_nrf2401_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.unlocked_ioctl = gt210_nrf2401_ioctl,
.compat_ioctl = gt210_nrf2401_ioctl,
.open = gt210_nrf2401_open,
.release = gt210_nrf2401_release,
};
/***** write and read reg ****/
static int gt210_nrf2401_write_reg (struct gt210_nrf2401_info *info,
unsigned char reg, unsigned char value)
{
int ret;
unsigned char tx_buf[4]={0};
unsigned char rx_buf[4]={0};
tx_buf[0] = reg ;
tx_buf[1] = value;
//ret = spi_write_then_read(info->spi_dev, tx_buf, 2, rx_buf, 1);
ret = spi_write(info->spi_dev, tx_buf, 2);
if (ret)
dprintk("failed to write reg: "
"addr=0x%02x, status=0x%02x, value=0x%02x, ret = %d\n",
reg, rx_buf[0], tx_buf[1],ret);
return ret;
}
static int gt210_nrf2401_read_reg (struct gt210_nrf2401_info *info,
unsigned char reg,unsigned char *value)
{
unsigned char tx_buf[4];
unsigned char rx_buf[4]={0xff};
int ret;
tx_buf[0] = reg;
//tx_buf[1] = reg;
ret = spi_write_then_read(info->spi_dev, tx_buf, 1, rx_buf, 2);
if (ret)
dprintk("failed to read reg: "
"addr=0x%02x, status=0x%02x, value=0x%02x, ret = %d\n",
reg, rx_buf[0], rx_buf[1],ret);
else
*value = rx_buf[1];
return ret;
}
static int gt210_nrf2401_read_status(struct gt210_nrf2401_info *info,
unsigned char reg,unsigned char *value)
{
unsigned char tx_buf[4];
unsigned char rx_buf[4];
int ret;
tx_buf[0] = reg ;
ret = spi_write_then_read(info->spi_dev, tx_buf, 1, rx_buf, 2);
if (ret)
dprintk("failed to read status: "
"addr=0x%02x, status=0x%02x, ret = %d\n",
reg, rx_buf[0],ret);
else
*value = rx_buf[0];
return ret;
}
static int gt210_nrf2401_write_buf(struct gt210_nrf2401_info *info,
unsigned char reg, unsigned char *buf,
unsigned char len)
{
int ret;
unsigned char tx_buf[NRF2401_PIPE_LEN+ 4];
unsigned char rx_buf[4];
tx_buf[0] = reg ;
memcpy(&tx_buf[1], buf, len);
//ret = spi_write_then_read(info->spi_dev, tx_buf, len + 1, rx_buf, 1);
ret = spi_write(info->spi_dev, tx_buf, len+1);
if (ret)
dprintk("failed to write buf: "
"addr=0x%02x, status=0x%02x, value=0x%02x, ret = %d\n",
reg, rx_buf[0], *buf,ret);
return ret;
}
/***** the two read buf function is both good on here *****/
#if 0
static int gt210_nrf2401_read_buf(struct gt210_nrf2401_info *info,
unsigned char reg, unsigned char *buf,
unsigned char len)
{
int i = 0;
int ret = 0;
for(i = 0; i < len; i++, buf++){
ret = gt210_nrf2401_read_reg(info, reg, buf);
}
return ret;
}
#else
static int gt210_nrf2401_read_buf(struct gt210_nrf2401_info *info,
unsigned char reg, unsigned char *buf,
unsigned char len)
{
u8 tx_buf[NRF2401_PIPE_LEN + 1] = {0};
u8 rx_buf[NRF2401_PIPE_LEN + 1] = {0};
int ret;
tx_buf[0] = reg ;
ret = spi_write_then_read(info->spi_dev, tx_buf, 1, rx_buf, len + 1);
if (ret)
dprintk("failed to read buf: "
"addr=0x%02x, status=0x%02x,value=0x%02x, ret = %d\n",
reg, rx_buf[0], rx_buf[1], ret);
memcpy(buf, &rx_buf[1], len); /* skip the first status byte */
return ret;
}
#endif
/***** chip set function *****/
static int gt210_nrf2401_init_chip(struct gt210_nrf2401_info *info)
{
struct gt210_nrf2401_platdata *pdata = info->pdata;
int ret = 0;
unsigned char value=0xff;
(info->pdata->clear_cepin)(pdata);
gt210_nrf2401_write_reg(info, WRITE_REG1 | EN_AA,
info->pdata->en_aa);
//msleep(10);
dprintk("write en aa reg: addr=0x%02x, value=0x%02x\n", EN_AA, info->pdata->en_aa);
gt210_nrf2401_read_reg(info,READ_REG1 | EN_AA, &value);
dprintk("read en aa reg: addr=0x%02x, value=0x%02x\n", EN_AA, value);
gt210_nrf2401_write_reg(info, WRITE_REG1 | EN_RXADDR,
info->pdata->en_rxaddr);
gt210_nrf2401_write_reg(info, WRITE_REG1 | RF_CH,
info->pdata->rf_ch);
gt210_nrf2401_write_reg(info, WRITE_REG1 | SETUP_AW,
info->pdata->setup_aw);
gt210_nrf2401_write_reg(info, WRITE_REG1 | SETUP_RETR,
info->pdata->setup_retr);
gt210_nrf2401_write_reg(info, WRITE_REG1 | RF_CH,
info->pdata->rf_ch);
gt210_nrf2401_write_reg(info, WRITE_REG1 | RF_SETUP,
info->pdata->rf_setup);
gt210_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P0,
info->pdata->rx_pw_p0);
gt210_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P1,
info->pdata->rx_pw_p1);
gt210_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P2,
info->pdata->rx_pw_p2);
gt210_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P3,
info->pdata->rx_pw_p3);
gt210_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P4,
info->pdata->rx_pw_p4);
gt210_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P5,
info->pdata->rx_pw_p5);
gt210_nrf2401_write_reg(info, WRITE_REG1 | CONFIG, 0x0f);
dprintk("write config reg: addr=0x%02x, value=0x%02x\n", CONFIG, 0x0f);
gt210_nrf2401_read_reg(info,READ_REG1 | CONFIG, &value);
dprintk("read config reg: addr=0x%02x, value=0x%02x\n", CONFIG, value);
(info->pdata->set_cepin)(pdata);
return ret;
}
static int gt210_nrf2401_deinit_chip(struct gt210_nrf2401_info *info)
{
struct gt210_nrf2401_platdata *pdata = info->pdata;
int ret;
(info->pdata->clear_cepin)(pdata);
gt210_nrf2401_write_reg(info, WRITE_REG1 | CONFIG, 0x78);
(info->pdata->set_cepin)(pdata);
return ret;
}
static int gt210_nrf2401_init_op(struct gt210_nrf2401_info *info)
{ dprintk("gt210_nrf2401_init_op()\n");
struct gt210_nrf2401_platdata *pdata = info->pdata;
int ret;
ret = request_irq(info->irq, gt210_nrf2401_irq,
info->pdata->irq_flags, info->spi_dev->modalias, info);
if(ret < 0){
dev_err(&info->spi_dev->dev,"failed to request irq: %d, error=%d",
info->irq, ret);
ret = -EBUSY;
return ret;
}
if(pdata->init_pin)
pdata->init_pin(pdata);
gt210_nrf2401_init_chip(info);
return ret;
}
static int gt210_nrf2401_deinit_op(struct gt210_nrf2401_info *info)
{ dprintk("gt210_nrf2401_deinit_op()\n");
struct gt210_nrf2401_platdata *pdata = info->pdata;
int ret;
free_irq(info->irq, info);
gt210_nrf2401_deinit_chip(info);
if(pdata->exit_pin)
pdata->exit_pin(pdata);
return ret;
}
static int gt210_nrf2401_set_tx_addr(struct gt210_nrf2401_pipe *pipe)
{
struct gt210_nrf2401_info *info = pipe->info;
struct gt210_nrf2401_platdata *pdata = info->pdata;
int ret;
(info->pdata->clear_cepin)(pdata);
ret = gt210_nrf2401_write_buf(info, WRITE_REG1 | TX_ADDR,
pipe->addr, NRF2401_ADDR_LEN);
(info->pdata->set_cepin)(pdata);
return ret;
}
static int gt210_nrf2401_set_rx_addr(struct gt210_nrf2401_pipe *pipe)
{
struct gt210_nrf2401_info *info = pipe->info;
struct gt210_nrf2401_platdata *pdata = info->pdata;
int ret;
(info->pdata->clear_cepin)(pdata);
ret = gt210_nrf2401_write_buf(info,
WRITE_REG1 | RX_ADDR_P0 + pipe->addr_num,
pipe->addr,
(pipe->addr_num == NRF2401_ADDR_0 || pipe->addr_num == NRF2401_ADDR_1) ?
NRF2401_ADDR_LEN :
NRF2401_ADDR_LEN - 4 );
(info->pdata->set_cepin)(pdata);
return ret;
}
static int gt210_nrf2401_send_buf(struct gt210_nrf2401_pipe *pipe,
struct gt210_nrf2401_pbuf *pbuf)
{
struct gt210_nrf2401_info *info = pipe->info;
struct gt210_nrf2401_platdata *pdata = info->pdata;
int i = 0;
int ret = 0;
(info->pdata->clear_cepin)(pdata);
gt210_nrf2401_write_reg(info, WRITE_REG1 | STATUS,0xff);
gt210_nrf2401_write_reg(info, WRITE_REG1 | 0xe1,0);
gt210_nrf2401_write_reg(info, WRITE_REG1 | 0xe2,0);
gt210_nrf2401_write_reg(info, WRITE_REG1 | CONFIG, 0x0e);
//msleep(10);
ret = gt210_nrf2401_write_buf(info, WR_TX_PLOAD,
pbuf->pipe_buf, NRF2401_PIPE_LEN);
(info->pdata->set_cepin)(pdata);
return ret;
}
static int gt210_nrf2401_recv_buf(struct gt210_nrf2401_pipe *pipe)
{
struct gt210_nrf2401_info *info = pipe->info;
struct gt210_nrf2401_platdata *pdata = info->pdata;
int i = 0;
int ret = 0;
(info->pdata->clear_cepin)(pdata);
gt210_nrf2401_write_reg(info, WRITE_REG1 | STATUS,0xff);
gt210_nrf2401_write_reg(info, WRITE_REG1 | 0xe1,0);
gt210_nrf2401_write_reg(info, WRITE_REG1 | 0xe2,0);
gt210_nrf2401_write_reg(info, WRITE_REG1 | CONFIG, 0x0f);
//msleep(10);
(info->pdata->set_cepin)(pdata);
return ret;
}
/***** pipe buf help function *****/
static struct gt210_nrf2401_pbuf *gt210_nrf2401_alloc_pbuf(struct nrf2401_ioc_transfer *xfer)
{
struct gt210_nrf2401_pbuf *pbuf = NULL;
pbuf = kzalloc(sizeof(struct gt210_nrf2401_pbuf), GFP_KERNEL);
if(pbuf != NULL){
INIT_LIST_HEAD(&pbuf->list);
if(xfer != NULL)
memcpy(pbuf->pipe_buf, xfer->txrx_buf, NRF2401_PIPE_LEN);
}
return pbuf;
}
static void gt210_nrf2401_free_pbuf(struct gt210_nrf2401_pbuf *pbuf)
{
if(pbuf)
kfree(pbuf);
}
/***** help function *****/
static void gt210_nrf2401_timer(unsigned long data)
{ dprintk("gt210_nrf2401_timer()\n");
struct gt210_nrf2401_pipe *pipe = (struct gt210_nrf2401_pipe *)data;
//pipe->error = -ENXIO;
pipe->error = 0;
complete(&pipe->done);
}
static void gt210_nrf2401_tx_work(struct work_struct *work)
{ dprintk("gt210_nrf2401_tx_work()\n");
struct gt210_nrf2401_pipe *pipe =
container_of(work, struct gt210_nrf2401_pipe, work);
dev_info(&pipe->info->spi_dev->dev, "\n");
struct gt210_nrf2401_pbuf *pbuf, *tmpbuf;
while(pipe->has_packets > 0){
spin_lock(&pipe->lock);
if(pipe->pbuf == NULL && pipe->has_packets > 0){
pipe->pbuf = list_entry(pipe->head.next, struct gt210_nrf2401_pbuf, list);
//dev_info(&pipe->info->spi_dev->dev, "if(): pipe->pbuf = 0x%08x,\n", pipe->pbuf);
spin_unlock(&pipe->lock);
gt210_nrf2401_set_rx_addr(pipe);
gt210_nrf2401_send_buf(pipe, pipe->pbuf);
msleep(10);
break;
}else{
//dev_info(&pipe->info->spi_dev->dev, "else(): pipe->pbuf = 0x%08x,\n", pipe->pbuf);
tmpbuf = pipe->pbuf;
pipe->pbuf = NULL;
list_del(&tmpbuf ->list);
pipe->has_packets--;
spin_unlock(&pipe->lock);
gt210_nrf2401_free_pbuf(tmpbuf);
if(pipe->xfer && tmpbuf == pipe->xbuf){
complete(&pipe->done);
}
}
}
}
static void gt210_nrf2401_rx_work(struct work_struct *work)
{ dprintk("gt210_nrf2401_rx_work()\n");
struct gt210_nrf2401_pipe *pipe =
container_of(work, struct gt210_nrf2401_pipe, work);
struct gt210_nrf2401_pbuf *pbuf;
if(pipe->xfer && pipe->xfer->rw_mode == NRF2401_IOC_RW_BLOCK){
spin_lock(&pipe->lock);
if(pipe->has_packets > 0){
//dev_info(&pipe->info->spi_dev->dev, "list_del(): pipe->pbuf = 0x%08x,\n", pipe->pbuf);
pbuf = list_entry(pipe->head.next, struct gt210_nrf2401_pbuf, list);
list_del(pipe->head.next);
pipe->has_packets--;
spin_unlock(&pipe->lock);
memcpy(pipe->xfer->txrx_buf, pbuf->pipe_buf,
NRF2401_PIPE_LEN);
gt210_nrf2401_free_pbuf(pbuf);
complete(&pipe->done);
}else
spin_unlock(&pipe->lock);
}
}
/***** ioctl ops pass function *****/
static int gt210_nrf2401_set_chip(struct gt210_nrf2401_info *info,
struct nrf2401_ioc_transfer *xfer)
{
int ret = 0;
mutex_lock(&info->buf_lock);
if(info->tx_pipe ||
info->rx_pipe[0] ||
info->rx_pipe[1] ||
info->rx_pipe[2] ||
info->rx_pipe[3] ||
info->rx_pipe[4] ||
info->rx_pipe[5]){
ret = -EBUSY;
goto exit_1;
}
info->pdata->en_aa = xfer->txrx_buf[0];
info->pdata->en_rxaddr = xfer->txrx_buf[1];
info->pdata->setup_aw = xfer->txrx_buf[2];
info->pdata->setup_retr = xfer->txrx_buf[3];
info->pdata->rf_ch = xfer->txrx_buf[4];
info->pdata->rf_setup = xfer->txrx_buf[5];
info->pdata->rx_pw_p0 = xfer->txrx_buf[6];
info->pdata->rx_pw_p1 = xfer->txrx_buf[7];
info->pdata->rx_pw_p2 = xfer->txrx_buf[8];
info->pdata->rx_pw_p3 = xfer->txrx_buf[9];
info->pdata->rx_pw_p4 = xfer->txrx_buf[10];
info->pdata->rx_pw_p5 = xfer->txrx_buf[11];
ret = gt210_nrf2401_init_chip(info);
exit_1:
mutex_unlock(&info->buf_lock);
return ret;
}
static int gt210_nrf2401_get_chip(struct gt210_nrf2401_info *info,
struct nrf2401_ioc_transfer *xfer)
{
int ret = 0;
xfer->txrx_buf[0] = info->pdata->en_aa;
xfer->txrx_buf[1] = info->pdata->en_rxaddr;
xfer->txrx_buf[2] = info->pdata->setup_aw;
xfer->txrx_buf[3] = info->pdata->setup_retr;
xfer->txrx_buf[4] = info->pdata->rf_ch;
xfer->txrx_buf[5] = info->pdata->rf_setup;
xfer->txrx_buf[6] = info->pdata->rx_pw_p0;
xfer->txrx_buf[7] = info->pdata->rx_pw_p1;
xfer->txrx_buf[8] = info->pdata->rx_pw_p2;
xfer->txrx_buf[9] = info->pdata->rx_pw_p3;
xfer->txrx_buf[10] = info->pdata->rx_pw_p4;
xfer->txrx_buf[11] = info->pdata->rx_pw_p5;
return ret;
}
static int gt210_nrf2401_set_tx_pipe(struct gt210_nrf2401_info *info,
struct nrf2401_ioc_transfer *xfer)
{ dprintk("gt210_nrf2401_set_tx_pipe()\n");
//dev_info(&info->spi_dev->dev, "pipe = %d : 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
// xfer->addr_num, xfer->txrx_buf[4], xfer->txrx_buf[3],
// xfer->txrx_buf[2], xfer->txrx_buf[1], xfer->txrx_buf[0]);
struct gt210_nrf2401_pipe *pipe;
int ret;
mutex_lock(&info->buf_lock);
pipe = info->tx_pipe;
if(pipe){
if(pipe->has_packets){
ret = -EBUSY;
}else{
memcpy(pipe->addr, xfer->txrx_buf, NRF2401_ADDR_LEN);
ret = gt210_nrf2401_set_tx_addr(pipe);
}
goto exit_1;
}
pipe = kzalloc(sizeof(struct gt210_nrf2401_pipe), GFP_KERNEL);
if(pipe == NULL){
dev_err(&info->spi_dev->dev, "failed to allocate struct gt210_nrf2401_pipe{}\n");
ret = -ENOMEM;
goto exit_1;
}
info->tx_pipe = pipe;
pipe->mode = NRF2401_PIPE_TX_MODE;
pipe->addr_num = NRF2401_ADDR_0;
//pipe->delay_ms = xfer->delay_ms;
pipe->info = info;
pipe->callback = gt210_nrf2401_tx_callback;
INIT_LIST_HEAD(&pipe->head);
spin_lock_init(&pipe->lock);
mutex_init(&pipe->mutex);
init_completion(&pipe->done);
INIT_WORK(&pipe->work, gt210_nrf2401_tx_work);
setup_timer(&pipe->timer, gt210_nrf2401_timer, (unsigned long)pipe);
memcpy(pipe->addr, xfer->txrx_buf, NRF2401_ADDR_LEN);
ret = gt210_nrf2401_set_tx_addr(pipe);
exit_1:
mutex_unlock(&info->buf_lock);
return ret;
}
static int gt210_nrf2401_get_tx_pipe(struct gt210_nrf2401_info *info,
struct nrf2401_ioc_transfer *xfer)
{
struct gt210_nrf2401_pipe *pipe;
int ret = 0;
pipe = info->tx_pipe;
if(pipe){
memcpy(xfer->txrx_buf, pipe->addr, NRF2401_ADDR_LEN);
}else{
ret = -ENOENT;
}
return ret;
}
static int gt210_nrf2401_set_rx_pipe(struct gt210_nrf2401_info *info,
struct nrf2401_ioc_transfer *xfer)
{ dprintk("gt210_nrf2401_set_rx_pipe()\n");
//dev_info(&info->spi_dev->dev, "pipe = %d : 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
// xfer->addr_num, xfer->txrx_buf[4], xfer->txrx_buf[3],
// xfer->txrx_buf[2], xfer->txrx_buf[1], xfer->txrx_buf[0]);
struct gt210_nrf2401_pipe *pipe;
int ret;
int i=0;
mutex_lock(&info->buf_lock);
if(xfer->addr_num < NRF2401_ADDR_0 &&
xfer->addr_num > NRF2401_ADDR_5){
ret = -EINVAL;
goto exit_1;
}
pipe = info->rx_pipe[xfer->addr_num];
if(pipe){
if(pipe->has_packets || pipe->xfer){
ret = -EBUSY;
}else{
memcpy(pipe->addr, xfer->txrx_buf, NRF2401_ADDR_LEN);
ret = gt210_nrf2401_set_rx_addr(pipe);
}
goto exit_1;
}
pipe = kzalloc(sizeof(struct gt210_nrf2401_pipe), GFP_KERNEL);
if(pipe == NULL){
dev_err(&info->spi_dev->dev, "failed to allocate struct gt210_nrf2401_pipe{}\n");
ret = -ENOMEM;
goto exit_1;
}
pipe->mode = NRF2401_PIPE_RX_MODE;
pipe->addr_num = xfer->addr_num;
//pipe->delay_ms = xfer->delay_ms;
pipe->info = info;
pipe->callback = gt210_nrf2401_rx_callback;
INIT_LIST_HEAD(&pipe->head);
spin_lock_init(&pipe->lock);
mutex_init(&pipe->mutex);
init_completion(&pipe->done);
INIT_WORK(&pipe->work, gt210_nrf2401_rx_work);
setup_timer(&pipe->timer, gt210_nrf2401_timer, (unsigned long)pipe);
memcpy(pipe->addr, xfer->txrx_buf, NRF2401_ADDR_LEN);
info->rx_pipe[pipe->addr_num] = pipe ;
ret = gt210_nrf2401_set_rx_addr(pipe);
ret = gt210_nrf2401_recv_buf(pipe);
exit_1:
mutex_unlock(&info->buf_lock);
return ret;
}
static int gt210_nrf2401_get_rx_pipe(struct gt210_nrf2401_info *info,
struct nrf2401_ioc_transfer *xfer)
{
struct gt210_nrf2401_pipe *pipe;
int ret;
pipe = info->rx_pipe[xfer->addr_num];
if(pipe){
memcpy(xfer->txrx_buf, pipe->addr, NRF2401_ADDR_LEN);
}else{
ret = -ENOENT;
}
return ret;
}
static int gt210_nrf2401_write_pipe(struct gt210_nrf2401_info *info,
struct nrf2401_ioc_transfer *xfer)
{ dprintk("gt210_nrf2401_write_pipe(pipe addr = 0x%08x)\n", info->tx_pipe);
struct gt210_nrf2401_pipe *pipe;
struct gt210_nrf2401_pbuf *pbuf;
int ret = 0;
mutex_lock(&info->buf_lock);
pipe = info->tx_pipe;
if(pipe == NULL){
mutex_unlock(&info->buf_lock);
ret = -ENOENT;
return ret;
}else
mutex_unlock(&info->buf_lock);
mutex_lock(&pipe->mutex);
if(pipe->xfer && xfer->rw_mode == NRF2401_IOC_RW_BLOCK){
ret = -EBUSY;
goto exit_1;
}
pipe->xfer = xfer;
pbuf = gt210_nrf2401_alloc_pbuf(xfer);
if(pbuf == NULL){
dev_err(&info->spi_dev->dev, "failed to allocate struct gt210_nrf2401_pbuf{}\n");
ret = -ENOMEM;
goto exit_1;
}
pipe->xbuf = pbuf;
spin_lock(&pipe->lock);
list_add_tail(&pbuf->list, &pipe->head);
pipe->has_packets++;
if(pipe->has_packets == 1){
spin_unlock(&pipe->lock);
schedule_work(&pipe->work);
}else
spin_unlock(&pipe->lock);
if(xfer->rw_mode == NRF2401_IOC_RW_NOBLOCK){
ret = 0;
}else if(xfer->rw_mode == NRF2401_IOC_RW_BLOCK){
if (xfer->delay_ms)
mod_timer(&pipe->timer, jiffies + msecs_to_jiffies(xfer->delay_ms));
wait_for_completion(&pipe->done);
ret = pipe->error;
}
exit_1:
pipe->xfer = NULL;
pipe->xbuf = NULL;
mutex_unlock(&pipe->mutex);
return ret;
}
static int gt210_nrf2401_read_pipe(struct gt210_nrf2401_info *info,
struct nrf2401_ioc_transfer *xfer)
{ dprintk("gt210_nrf2401_read_pipe()\n");
struct gt210_nrf2401_pipe *pipe = info->rx_pipe[xfer->addr_num];
struct gt210_nrf2401_pbuf *pbuf ;
int ret = 0;
int i = 0;
mutex_lock(&info->buf_lock);
pipe = info->rx_pipe[xfer->addr_num];
if(pipe == NULL){
mutex_unlock(&info->buf_lock);
ret = -ENOENT;
return ret;
}else
mutex_unlock(&info->buf_lock);
mutex_lock(&pipe->mutex);
if(pipe->xfer && xfer->rw_mode == NRF2401_IOC_RW_BLOCK){
ret = -EBUSY;
goto exit_1;
}
pipe->xfer = xfer;
if(xfer->rw_mode == NRF2401_IOC_RW_NOBLOCK){
spin_lock(&pipe->lock);
if(pipe->has_packets > 0){
pbuf = list_entry(pipe->head.next, struct gt210_nrf2401_pbuf, list);
list_del(pipe->head.next);
pipe->has_packets--;
spin_unlock(&pipe->lock);
memcpy(pipe->xfer->txrx_buf, pbuf->pipe_buf,
NRF2401_PIPE_LEN);
gt210_nrf2401_free_pbuf(pbuf);
ret = 0;
}else{
spin_unlock(&pipe->lock);
ret = -ENOENT;
}
}else if(xfer->rw_mode == NRF2401_IOC_RW_BLOCK){
if (xfer->delay_ms)
mod_timer(&pipe->timer,jiffies + msecs_to_jiffies(xfer->delay_ms));
schedule_work(&pipe->work);
wait_for_completion(&pipe->done);
ret = pipe->error;
}
exit_1:
pipe->xfer = NULL;
mutex_unlock(&pipe->mutex);
return ret;
}
static int gt210_nrf2401_pass_op(struct gt210_nrf2401_info *info,
struct nrf2401_ioc_transfer *xfer)
{ dprintk("gt210_nrf2401_pass_op()\n");
int ret = 0;
switch(xfer->ioc_type){
case NRF2401_IOC_NONE_0:
break;
case NRF2401_IOC_SET_CHIP:
ret = gt210_nrf2401_set_chip(info, xfer);
break;
case NRF2401_IOC_GET_CHIP:
ret = gt210_nrf2401_get_chip(info, xfer);
break;
case NRF2401_IOC_SET_RX_PIPE:
ret = gt210_nrf2401_set_rx_pipe(info, xfer);
break;
case NRF2401_IOC_GET_RX_PIPE:
ret = gt210_nrf2401_get_rx_pipe(info, xfer);
break;
case NRF2401_IOC_SET_TX_PIPE:
ret = gt210_nrf2401_set_tx_pipe(info, xfer);
break;
case NRF2401_IOC_GET_TX_PIPE:
ret = gt210_nrf2401_get_tx_pipe(info, xfer);
break;
case NRF2401_IOC_WRITE_PIPE:
ret = gt210_nrf2401_write_pipe(info, xfer);
break;
case NRF2401_IOC_READ_PIPE:
ret = gt210_nrf2401_read_pipe(info, xfer);
break;
default:
break;
}
return ret;
}
static long gt210_nrf2401_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{ dprintk("gt210_nrf2401_ioctl()\n");
struct gt210_nrf2401_info *info;
struct spi_device *spi_dev;
struct nrf2401_ioc_transfer *xfer;
unsigned n_transfer;
u32 tmp = 0, offset = 0, len = 0;
int err = 0, ret = 0;
if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC){
dprintk("failed to get good magic code: \n", _IOC_TYPE(cmd));
return -ENOTTY;
}
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE,
(void __user *)arg, _IOC_SIZE(cmd));
if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ,
(void __user *)arg, _IOC_SIZE(cmd));
if (err){
dprintk("failed to get read or write addr permission: \n", err);
return -EFAULT;
}
info = filp->private_data;
spin_lock_irq(&info->spi_lock);
spi_dev = spi_dev_get(info->spi_dev);
spin_unlock_irq(&info->spi_lock);
if (spi_dev == NULL){
dprintk("failed to get alive spi device : \n");
return -ESHUTDOWN;
}
//mutex_lock(&info->buf_lock);
switch (cmd) {
default:
if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
|| _IOC_DIR(cmd) != _IOC_WRITE) {
dprintk("failed to get used massage : \n");
ret = -ENOTTY;
break;
}
tmp = _IOC_SIZE(cmd);
if ((tmp % sizeof(struct nrf2401_ioc_transfer)) != 0) {
dprintk("failed to get aligned massage : \n");
ret = -EINVAL;
break;
}
n_transfer = tmp / sizeof(struct nrf2401_ioc_transfer);
if (n_transfer == 0 || n_transfer > 1){
dprintk("failed to support more massage : \n");
ret = -EINVAL;
break;
}
xfer = kmalloc(tmp, GFP_KERNEL);
if (!xfer) {
dprintk("failed to allocate struct nrf2401_ioc_transfer{}: \n");
ret = -ENOMEM;
break;
}
if (__copy_from_user(xfer, (void __user *)arg, tmp)) {
dprintk("failed to copy k space from u space: \n");
kfree(xfer);
ret = -EFAULT;
break;
}
ret = gt210_nrf2401_pass_op(info, xfer);
if(ret){
dprintk("failed to pass operation: ret = %d\n", ret);
ret = -EFAULT;
}else{
switch(xfer->ioc_type){
case NRF2401_IOC_GET_CHIP:
case NRF2401_IOC_GET_RX_PIPE:
case NRF2401_IOC_GET_TX_PIPE:
case NRF2401_IOC_READ_PIPE:
//len = NRF2401_PIPE_LEN + NRF2401_PIPE_PLUS;
//offset = (tmp - len);
len = tmp;
offset = 0;
if(__copy_to_user((u8 __user *)(arg) + offset,
((u8 *)xfer) + offset,
len )){
dprintk("failed to copy k space to u space: \n");
ret = -EFAULT;
}
break;
default :
break;
}
;;;
}
kfree(xfer);
break;
/***** spi inferface mode set *****/
case SPI_IOC_RD_MODE:
ret = __put_user(spi_dev->mode & SPI_MODE_MASK,(__u8 __user *)arg);
break;
case SPI_IOC_RD_LSB_FIRST:
ret = __put_user((spi_dev->mode & SPI_LSB_FIRST) ? 1 : 0,(__u8 __user *)arg);
break;
case SPI_IOC_RD_BITS_PER_WORD:
ret = __put_user(spi_dev->bits_per_word, (__u8 __user *)arg);
break;
case SPI_IOC_RD_MAX_SPEED_HZ:
ret = __put_user(spi_dev->max_speed_hz, (__u32 __user *)arg);
break;
case SPI_IOC_WR_MODE:
ret = __get_user(tmp, (u8 __user *)arg);
if (ret == 0) {
u8 save = spi_dev->mode;
if (tmp & ~SPI_MODE_MASK) {
ret = -EINVAL;
break;
}
tmp |= spi_dev->mode & ~SPI_MODE_MASK;
spi_dev->mode = (u8)tmp;
ret = spi_setup(spi_dev);
if (ret < 0)
spi_dev->mode = save;
else
dev_dbg(&spi_dev->dev, "spi mode %02x\n", tmp);
}
break;
case SPI_IOC_WR_LSB_FIRST:
ret = __get_user(tmp, (__u8 __user *)arg);
if (ret == 0) {
u8 save = spi_dev->mode;
if (tmp)
spi_dev->mode |= SPI_LSB_FIRST;
else
spi_dev->mode &= ~SPI_LSB_FIRST;
ret = spi_setup(spi_dev);
if (ret < 0)
spi_dev->mode = save;
else
dev_dbg(&spi_dev->dev, "%csb first\n",tmp ? 'l' : 'm');
}
break;
case SPI_IOC_WR_BITS_PER_WORD:
ret = __get_user(tmp, (__u8 __user *)arg);
if (ret == 0) {
u8 save = spi_dev->bits_per_word;
spi_dev->bits_per_word = tmp;
ret = spi_setup(spi_dev);
if (ret < 0)
spi_dev->bits_per_word = save;
else
dev_dbg(&spi_dev->dev, "%d bits per word\n", tmp);
}
break;
case SPI_IOC_WR_MAX_SPEED_HZ:
ret = __get_user(tmp, (__u32 __user *)arg);
if (ret == 0) {
u32 save = spi_dev->max_speed_hz;
spi_dev->max_speed_hz = tmp;
ret = spi_setup(spi_dev);
if (ret < 0)
spi_dev->max_speed_hz = save;
else
dev_dbg(&spi_dev->dev, "%d Hz (max)\n", tmp);
}
break;
}
//mutex_unlock(&info->buf_lock);
spi_dev_put(spi_dev);
return ret;
}
static int gt210_nrf2401_open(struct inode *inode, struct file *filp)
{ dprintk("gt210_nrf2401_open()\n");
struct gt210_nrf2401_info *info;
int ret = -ENOENT;
mutex_lock(&device_list_lock);
list_for_each_entry(info, &device_list, device_entry) {
if (info->devt == inode->i_rdev) {
ret = 0;
break;
}
}
if (ret == 0) {
if(info->users == 0){
#ifdef GT210_NRF2401_TEST
;
#else
ret = gt210_nrf2401_init_op(info);
#endif
if(ret < 0){
dev_err(&info->spi_dev->dev, "failed to init nrf2401\n");
goto exit_1;
}
}
info->users++;
filp->private_data = info;
nonseekable_open(inode, filp);
} else
dev_err(&info->spi_dev->dev, "failed to get minor %d\n", iminor(inode));
exit_1:
mutex_unlock(&device_list_lock);
dprintk("gt210_nrf2401_open(): end, ret = %d\n", ret);
return ret;
}
static int gt210_nrf2401_release(struct inode *inode, struct file *filp)
{ dprintk("gt210_nrf2401_release()\n");
struct gt210_nrf2401_info *info;
struct gt210_nrf2401_pipe *pipe;
struct gt210_nrf2401_pbuf *pbuf;
int ret = 0;
mutex_lock(&device_list_lock);
info = filp->private_data;
filp->private_data = NULL;
info->users--;
if (!info->users) {
#ifdef GT210_NRF2401_TEST
;
#else
ret = gt210_nrf2401_deinit_op(info);
#endif
if(ret < 0){
dev_err(&info->spi_dev->dev, "failed to deinit nrf2401\n");
goto exit_1;
}
int dofree;
int i = 0;
pipe = info->tx_pipe;
if(pipe != NULL){
while(! list_empty(&pipe->head)){
pbuf = list_entry(pipe->head.next, struct gt210_nrf2401_pbuf, list);
list_del(pipe->head.next);
gt210_nrf2401_free_pbuf(pbuf);
}
kfree(pipe);
info->tx_pipe = NULL;
}
for(i=0; i < NRF2401_ADDR_NUM; i++){
pipe = info->rx_pipe[i];
if(pipe != NULL){
while(! list_empty(&pipe->head)){
pbuf = list_entry(pipe->head.next, struct gt210_nrf2401_pbuf, list);
list_del(pipe->head.next);
gt210_nrf2401_free_pbuf(pbuf);
}
kfree(pipe);
info->rx_pipe[i] = NULL;
}
}
spin_lock_irq(&info->spi_lock);
dofree = (info->spi_dev == NULL);
spin_unlock_irq(&info->spi_lock);
if (dofree) {
kfree(info);
}
}
exit_1:
mutex_unlock(&device_list_lock);
dprintk("gt210_nrf2401_release(): end\n");
return ret ;
}
/***** interrupt and callback function ****/
static int gt210_nrf2401_tx_callback(struct gt210_nrf2401_pipe *pipe,
struct gt210_nrf2401_pbuf *pbuf)
{
schedule_work(&pipe->work);
}
static int gt210_nrf2401_rx_callback(struct gt210_nrf2401_pipe *pipe,
struct gt210_nrf2401_pbuf *pbuf)
{
spin_lock(&pipe->lock);
list_add_tail(&pbuf->list, &pipe->head);
pipe->has_packets++;
spin_unlock(&pipe->lock);
schedule_work(&pipe->work);
}
static void gt210_nrf2401_irq_rx(struct gt210_nrf2401_info *info, int addr_num)
{
struct gt210_nrf2401_pipe *pipe = info->rx_pipe[addr_num];
struct gt210_nrf2401_pbuf *pbuf;
int i=0;
if(pipe == NULL)
return ;
pbuf = gt210_nrf2401_alloc_pbuf(NULL);
gt210_nrf2401_read_buf(info, READ_REG1 |RD_RX_PLOAD,
pbuf->pipe_buf, NRF2401_PIPE_LEN);
//gt210_nrf2401_write_reg(info, 0xe2,0);
gt210_nrf2401_recv_buf(pipe);
pbuf->mseconds = jiffies_to_msecs(jiffies);
pbuf->addr_num = addr_num;
/*
dprintk("read FIFO data: pipe num=%d", addr_num );
for(i = 0; i<NRF2401_PIPE_LEN; i++){
if(i%4 == 0) dprintk("\n");
dprintk("0x%02x ",pbuf->pipe_buf[i]);
}
dprintk("\nread FIFO data: end\n");
*/
pipe->packets++;
pipe->error = 0;
pipe->callback(pipe, pbuf);
}
static void gt210_nrf2401_irq_tx(struct gt210_nrf2401_info *info,
int addr_num)
{
struct gt210_nrf2401_pipe *pipe = info->tx_pipe;
if(pipe == NULL)
return ;
pipe->error = 0;
pipe->packets++;
//gt210_nrf2401_write_reg(info, 0xe1,0);
gt210_nrf2401_set_rx_addr(info->rx_pipe[addr_num]);
gt210_nrf2401_recv_buf(pipe);
pipe->callback(pipe, pipe->pbuf);
}
static void gt210_nrf2401_irq_tx_error(struct gt210_nrf2401_info *info,
int addr_num)
{
struct gt210_nrf2401_pipe *pipe = info->tx_pipe;
if(pipe == NULL)
return ;
pipe->error = -EIO;
pipe->err_packets++;
pipe->packets++;
//gt210_nrf2401_write_reg(info, 0xe1,0);
gt210_nrf2401_set_rx_addr(info->rx_pipe[addr_num]);
gt210_nrf2401_recv_buf(pipe);
pipe->callback(pipe, pipe->pbuf);
}
static void gt210_nrf2401_irq_work(struct work_struct *work)
{ dprintk("gt210_nrf2401_irq_work()\n");
struct gt210_nrf2401_info *info =
container_of(work, struct gt210_nrf2401_info, irq_work);
unsigned char status;
int i=0;
int addr_num=0;
gt210_nrf2401_read_status(info, READ_REG1 |STATUS, &status);
dev_info(&info->spi_dev->dev,"read status reg: addr=0x%02x, value=0x%02x \n",
STATUS, status);
if(status & 0x40){ /***** rx ok *****/
if((status&0x0e)<=0x0a){
addr_num = (status&0x0e) >> 1;
}else
addr_num = 0;
gt210_nrf2401_irq_rx(info, addr_num);
}else if((status &0x20)>0){ /***** tx ok *****/
gt210_nrf2401_irq_tx(info, 0);
}else if((status &0x10)>0){ /***** tx error *****/
gt210_nrf2401_irq_tx_error(info, 0);
}
gt210_nrf2401_write_reg(info, WRITE_REG1 | STATUS, status);
return ;
}
static irqreturn_t gt210_nrf2401_irq(int irq, void *dev_id)
{ //dprintk("gt210_nrf2401_irq()\n");
struct gt210_nrf2401_info *info = dev_id;
schedule_work(&info->irq_work);
return IRQ_HANDLED;
}
/***** probe and remove function ****/
#ifdef GT210_NRF2401_TEST
static void gt210_nrf2401_test_chip(struct gt210_nrf2401_info *info)
{
int i = 0;
int loops = 0;
int ret = 0;
struct nrf2401_ioc_transfer xfer={
.ioc_type = NRF2401_IOC_SET_RX_PIPE,
.addr_num = 0,
};
for(i = 0; i<NRF2401_ADDR_LEN; i++){
xfer.txrx_buf[i] = (u8)0x01;
}
ret = gt210_nrf2401_pass_op(info, &xfer);
if(ret < 0 ){
dev_err(&info->spi_dev->dev, "failed to set rx addr(%d)\n", xfer.addr_num);
}else{
dev_info(&info->spi_dev->dev,
"good to set rx addr(%d) : 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
xfer.addr_num,
xfer.txrx_buf[0], xfer.txrx_buf[1],
xfer.txrx_buf[2], xfer.txrx_buf[3],
xfer.txrx_buf[4]);
}
xfer.ioc_type = NRF2401_IOC_SET_TX_PIPE;
for(i = 0; i<NRF2401_ADDR_LEN; i++){
xfer.txrx_buf[i] = (u8)0x11;
}
ret = gt210_nrf2401_pass_op(info, &xfer);
if(ret < 0 ){
dev_err(&info->spi_dev->dev, "failed to set tx addr\n");
}else{
dev_info(&info->spi_dev->dev,
"good to set tx addr(%d) : 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
xfer.addr_num,
xfer.txrx_buf[0], xfer.txrx_buf[1],
xfer.txrx_buf[2], xfer.txrx_buf[3],
xfer.txrx_buf[4]);
}
xfer.ioc_type = NRF2401_IOC_WRITE_PIPE;
//xfer.ioc_type = NRF2401_IOC_READ_PIPE;
for(i = 0; i<NRF2401_PIPE_LEN; i++){
xfer.txrx_buf[i] = (u8)0x24;
}
xfer.addr_num = 0;
//xfer.rw_mode = NRF2401_IOC_RW_BLOCK;
xfer.rw_mode = NRF2401_IOC_RW_NOBLOCK;
loops = 1;
while(loops--){
ret = gt210_nrf2401_pass_op(info, &xfer);
if(ret <0){
dev_err(&info->spi_dev->dev, "failed to send data\n");
}else{
dev_info(&info->spi_dev->dev, "good to send data:");
for(i = 0; i< NRF2401_PIPE_LEN; i++){
if(i%4 == 0)
dprintk("\n");
dprintk("0x%02x ",xfer.txrx_buf[i] );
}
dprintk("\n");
}
msleep(1000);
}
}
#endif
static int gt210_nrf2401_probe(struct spi_device *spi_dev)
{ dprintk("\n\ngt210_nrf2401_probe(id=%d.%d)\n", spi_dev->master->bus_num, spi_dev->chip_select);
struct gt210_nrf2401_info *info;
struct gt210_nrf2401_platdata *pdata;
unsigned long minor;
int ret;
pdata = spi_dev->dev.platform_data;
if (pdata == NULL) {
dev_err(&spi_dev->dev,"failed to get platform_data\n");
return -EINVAL;
}
info = kzalloc(sizeof(struct gt210_nrf2401_info), GFP_KERNEL);
if (info == NULL) {
dev_err(&spi_dev->dev,"failed to allocate struct gt210_nrf2401_info{}\n");
return -ENOMEM;
}
info->pdata = pdata;
info->irq = spi_dev->irq;
info->spi_dev = spi_dev;
memcpy(info->name, "gt210_nrf2401", sizeof("gt210_nrf2401"));
INIT_LIST_HEAD(&info->device_entry);
spin_lock_init(&info->spi_lock);
mutex_init(&info->buf_lock);
INIT_WORK(&info->irq_work, gt210_nrf2401_irq_work);
spi_set_drvdata(spi_dev, info);
mutex_lock(&device_list_lock);
minor = find_first_zero_bit(minors, N_SPI_MINORS);
if (minor < N_SPI_MINORS) {
struct device *dev;
info->devt = MKDEV(SPICHAR_MAJOR, minor);
dev = device_create(gt210_nrf2401_class, &spi_dev->dev, info->devt,
info, "nrf2401-%d.%d",
spi_dev->master->bus_num, spi_dev->chip_select);
if(IS_ERR(dev)){
dev_dbg(&spi_dev->dev, "failed to create device \n");
ret = IS_ERR(dev) ;
goto exit_1;
}
info->dev = dev;
} else {
dev_err(&spi_dev->dev, "failed to allocate minor number \n");
ret = -ENODEV;
goto exit_1;
}
set_bit(minor, minors);
list_add(&info->device_entry, &device_list);
mutex_unlock(&device_list_lock);
#ifdef GT210_NRF2401_TEST
gt210_nrf2401_init_op(info);
gt210_nrf2401_test_chip(info);
#else
;
#endif
return 0;
exit_1:
kfree(info);
spi_set_drvdata(spi_dev, NULL);
return ret;
}
static int gt210_nrf2401_remove(struct spi_device *spi_dev)
{ dprintk("gt210_nrf2401_remove(id=%d.%d)\n",
spi_dev->master->bus_num, spi_dev->chip_select);
struct gt210_nrf2401_info *info = spi_get_drvdata(spi_dev);
if(info == NULL)
return 0;
#ifdef GT210_NRF2401_TEST
gt210_nrf2401_deinit_op(info);
#else
;
#endif
spin_lock_irq(&info->spi_lock);
info->spi_dev = NULL;
spi_set_drvdata(spi_dev, NULL);
spin_unlock_irq(&info->spi_lock);
mutex_lock(&device_list_lock);
list_del(&info->device_entry);
device_destroy(gt210_nrf2401_class, info->devt);
info->dev = NULL;
clear_bit(MINOR(info->devt), minors);
if (info->users == 0)
kfree(info);
mutex_unlock(&device_list_lock);
return 0;
}
static struct spi_driver gt210_nrf2401_spi_driver = {
.driver = {
.name = SPI_DEVICE_NAME, /* nrf2401 != spidev*/
.owner = THIS_MODULE,
},
.probe = gt210_nrf2401_probe,
.remove = gt210_nrf2401_remove,
};
/***** init and exit ****/
static int __init gt210_nrf2401_init(void)
{ dprintk("gt210_nrf2401_init()\n");
int ret;
BUILD_BUG_ON(N_SPI_MINORS > 256);
ret = register_chrdev(SPICHAR_MAJOR, SPI_DEVICE_NAME, >210_nrf2401_fops);
if (ret < 0){
printk(KERN_ERR"failed to register char device\n");
ret = -EINVAL;
return ret;
}
gt210_nrf2401_class = class_create(THIS_MODULE, SPI_DEVICE_NAME);
if (IS_ERR(gt210_nrf2401_class)) {
printk(KERN_ERR"failed to create class\n");
ret = PTR_ERR(gt210_nrf2401_class);
goto exit_1;
}
ret = spi_register_driver(>210_nrf2401_spi_driver);
if (ret < 0) {
printk(KERN_ERR"failed to register spi driver\n");
goto exit_2;
}
return 0;
exit_2:
class_destroy(gt210_nrf2401_class);
gt210_nrf2401_class = NULL;
exit_1:
unregister_chrdev(SPICHAR_MAJOR,
gt210_nrf2401_spi_driver.driver.name);
return ret;
}
static void __exit gt210_nrf2401_exit(void)
{ dprintk("gt210_nrf2401_exit()\n");
spi_unregister_driver(>210_nrf2401_spi_driver);
class_destroy(gt210_nrf2401_class);
unregister_chrdev(SPICHAR_MAJOR,
gt210_nrf2401_spi_driver.driver.name);
}
module_init(gt210_nrf2401_init);
module_exit(gt210_nrf2401_exit);
MODULE_DESCRIPTION("GT2440 NRF2401 SPI Wireless Transceiver Device Driver");
MODULE_AUTHOR("Liguang13579<1659890447@qq.com>");
MODULE_LICENSE("GPL v2");
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。