2 Star 5 Fork 3

liguang13579 / Linux NRF24L01SPI Network Card Drivers

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
gt210_nrf2401.c 36.55 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
/*
* /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, &gt210_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(&gt210_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(&gt210_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");
C
1
https://gitee.com/liguang13579/Linux-NRF24L01SPI-Network-Card-Drivers.git
git@gitee.com:liguang13579/Linux-NRF24L01SPI-Network-Card-Drivers.git
liguang13579
Linux-NRF24L01SPI-Network-Card-Drivers
Linux NRF24L01SPI Network Card Drivers
master

搜索帮助