全志a33下生成设备节点/dev/spi0.0的步骤(全志a20下生成/dev/spidev2.0)

42 篇文章 2 订阅
9 篇文章 1 订阅
全志a33下生成设备节点/dev/spi0.0的步骤
(全志a20下生成/dev/spidev2.0)


公司需要用博通的BCM5892处理器和全志的a33通讯,为什么这样选择就不得而知了。


BCM5892共有5路SPI(0-4),用作从机的时候,只有5.5Mbps,用作主机的时候可以达到12Mbps。


以前的产品里面,已经占用了3路SPI。
现在还有SPI2(SD卡/TF卡)、SPI4(被打印机马达控制器占用)
SPI2为特殊SPI接口,用于读写SD卡/TF卡。
用作SPI主的时候,可以达到25Mbps。作从的速度未知?
最开始准备用SPI2,后来看SPI2为SD卡的专用接口(读写必须遵从SD卡的协议!),协议比较复杂,暂时放弃。


SPI4上的打印机被去掉了,于是暂时先用SPI4作为主SPI了,将全志a33作为SPI从机。
那就是将难度系数又提高了一个数量级。
你去找关于ARM的作为SPI从机的资料,保证收获很少。不信可以试试。


http://blog.csdn.net/yongan1006/article/details/7187774
spi从机驱动(lpc3250)


对 NXP 的lpc3250不熟悉,将来可以作为参考吧!
开发板比较贵,1000¥+,BAIDU之后感觉很少有人在用这种片子!


别人都建议我用USB/UART等等来通讯,资料丰富!


不管了,开工!
先调通 全志a33 作为主机的情况,这样资料比较多!


http://www.68idc.cn/help/makewebs/asks/20140620109431.html
Linux下SPI驱动开发


目标:在华清远见的FS_S5PC100平台上编写一个简单的spi驱动模块,在probe阶段实现对m25p10的ID号探测、flash擦除、flash状态读取


http://www.51ou.com/browse/linuxnh/29582.html
Linux下spi驱动开发(1)


http://www.embedu.org/Column/Column367.htm
Linux下spi驱动开发(1)



作者:刘老师,华清远见嵌入式学院讲师。


http://blog.163.com/wxiongn@126/blog/static/11788203820111126103811200/
linux spi驱动分析整理  




调试 SPI主的驱动的时候,都会在 /dev下生成一个设备节点 spi0.0:/dev/spi0.0。
这样就可以调试了。
最开始用的开发板:SINA33。


http://www.sinlinx.com/
芯灵思


sina33+LCD+TP+调试线+快递费=400¥出头


开发板比较便宜,提供 原理图的大部分 + BSP。
技术支持 比较不给力!官方没有自建开源论坛。
(付费的技术支持按项目收费,功能不搭理你!)








按照网上的资料(《android SPI设备驱动开发》),在menuconfig里面勾选需要的选项。
rootroot@rootroot-E400:~/wyb/sina33/lichee/linux-3.4$ 


Device Drivers --->
[*] SPI support --->
--- SPI support
[*]   Debug support for SPI drivers
     *** SPI Master Controller Drivers ***
< >   Altera SPI Controller
-*-   Utilities for Bitbanging SPI masters
<*>   GPIO-based bitbanging SPI Master
< >   OpenCores tiny SPI
<*>   SUN7I SPI Controller
< >   Xilinx SPI controller common module
<*>   DesignWare SPI controller core support
<*>     Memory-mapped io interface driver for DW SPI core
     *** SPI Protocol Masters ***
<*>   User mode SPI device driver support
< >   Infineon TLE62X0 (for power switching)


配置fex文件。
S:\lichee\tools\pack\chips\sun8iw5p1\configs\y3\sys_config.fex


;----------------------------------------------------------------------------------
;SPI controller configuration
;spi_used       = SPIx enable
;spi_cs_bitmap  = SPI bit mapping
;----------------------------------------------------------------------------------
[spi0]
spi_used       = 1
spi_cs_bitmap  = 1
spi_mosi       = port:PC00<3><default><default><default>
spi_miso       = port:PC01<3><default><default><default>
spi_sclk       = port:PC02<3><default><default><default>
spi_cs0        = port:PC03<3><1><default><default>


[spi1]
spi_used       = 0
spi_cs_bitmap  = 1
spi_cs0        = port:PA00<2><1><default><default>
spi_sclk       = port:PA01<2><default><default><default>
spi_mosi       = port:PA02<2><default><default><default>
spi_miso       = port:PA03<2><default><default><default>


;----------------------------------------------------------------------------------
;SPI device configuration
;spi_dev_num: number of spi devices
;----------------------------------------------------------------------------------
[spi_devices]
spi_dev_num = 1


;----------------------------------------------------------------------------------
;[spi_board0] spi device configuration
;modalias      = spi device name
;max_speed_hz  = max transfer speed
;bus_num       = bus ID
;chip_select   = chip select, 0,1
;mode          = SPI transfer mode
;----------------------------------------------------------------------------------
[spi_board0]
;modalias      = "at25df641"
modalias      = "spidev"
max_speed_hz  = 50000000
bus_num       = 0
chip_select   = 0
mode          = 0








;----------------------------------------------------------------------------------
;[nandx_para]
;nand_support_2ch    = support dual channel
;nand0_used          = nand0使能标识
;----------------------------------------------------------------------------------
[nand0_para]
nand_support_2ch    = 0


nand0_used          = 0
;nand0_we            = port:PC00<2><default><default><default>
;nand0_ale           = port:PC01<2><default><default><default>
;nand0_cle           = port:PC02<2><default><default><default>
;nand0_ce1           = port:PC03<2><default><default><default>




不行。








被 逼急了,在网上
看见 方糖电子的人写的资料:
http://wenku.baidu.com/link?url=HXmii9SUDBzc_exdje05_cIjGHlAVMYkCCg44v9UoRXvR3gxcQSUxvpK3pUIQ_4kNgfWhPkYJmxVafgGX8UNIXo0xEmhbqypNdHx1LQjx7y
android SPI设备驱动开发
以为找到板子就万事大吉了。


找a20的开发板,看见有:
http://www.smartdevicetech.com/
深圳市视美泰通讯技术有限公司


核心板(零售价350¥/1k可以做到230-240)+主板+LCD屏幕+TP = 1000¥
有点贵。算了。他们是做 电子广告牌的核心板的。这个行业很多人用A20的方案。
技术支持是收费的!








http://www.cubietech.com/
方糖电子 英文官网。


http://www.cubie.cc/
方糖电子 的官方技术论坛,问问题还是有人回的!


之后直接找到 方糖电子,核心板 + 3.5寸LCD + TP + 调试线 + 快递= 500¥
电源头(标称需要5V/2A,25¥有点贵。我用的是5V/1.5A的)自己有,就没有买了。


http://www.cubie.cc/forum.php?mod=viewthread&tid=3404&highlight=a80
CB4:CC-A80荣耀开盘,国内率先预售


在 TAOBAO 有三家代理商。
销售中心请前往:采蜜数码 EWELL 风火轮


cubieboard1是采用的全志A10的方案(ARM内核:Cortex A8。)
《android SPI设备驱动开发》图带的cubietruck使用A20,但是较贵。


按照 论坛 提供的编译方式编译/烧录 cubieboard2,
http://www.cubie.cc/forum.php?mod=viewthread&tid=4181
Cubieboard2 android编译及制作固件


首先 按照 网盘的说明调通了LCD显示(虽然省钱LCD也可以不买的!),虽然是 急需的。
个人习惯问题,有显示,可能启动正常了,放心。


接着调试 SPI 接口,发现 文档《android SPI设备驱动开发》貌似有问题。
板子跑起来了,SPI使劲不同,但是时间花了不少!
给 support@cubietech.com 和 作者 Payne[payne@cubietech.com] 本人发邮件。


遗憾,Payne休假了。和 support@cubietech.com 沟通几天之后,他终于决定自己拿一套文档中的环境,在cubietruck上面测试!
2)在百度云下载源码压缩包:  
http://pan.baidu.com/s/1kTFXnPP  


确认文档有点问题。


一切都回到了原点。






解决问题的过程中尝试过的方向:
1、是编译cubieboard2,文档中用cubietruck的。
可以fex文件之类的配置,编译的cubietruck在cubieboard2上面运行不好。


2、fex配置文件中的GPIO口被被人占用了。通过 ; 注释掉。还是不行。


3、生成/dev/spi0.0不行,那尝试生成/dev/spi2.0行不?失败!
http://blog.csdn.net/yao_guet/article/details/37910573
Humming Bird A20 SPI2驱动编译


http://blog.csdn.net/jiangdou88/article/details/21288781
A20,SPI配置


4、尝试加printk打印一些消息。
S:\lichee\linux-3.4\drivers\video\sunxi\disp\dev_disp.c
结果发现加进去的prink显示不出来。


5、先调试好模块,然后将模块文件加载到:
S:\lichee\linux-3.4\drivers\spi\spidev.c
过分的是,测试的 节点 my_led 竟然没有生成!


6、午休之后,突然想起来,以前做 TP触摸屏 调试的时候,驱动加载有优先级/先后顺序的问题。
spidev.c 这个设备的驱动,肯定比SPI总线驱动的优先级低,修改 module_init 为 late_initcall,还是不行。


我放到 S:\lichee\linux-3.4\drivers\char 里面的字符设备节点也没有生成,修改成 late_initcall 也无效。


http://wenku.baidu.com/view/234eb1637e21af45b307a810.html
linux系统Nor Flash芯片初始化及驱动
注: late_initcall()优先级为 7, module_init()优先级为 6, 数值越低优先级越高


http://blog.chinaunix.net/uid-29570002-id-4387097.html
Linux驱动late_initcall和module_init相关分析


7、绝境中的时候,没有办法的办法了。
因为 全志a33 自己确认是支持模块的,将 spidev.c 编译成模块。奇迹出现了:
shell@astar-y3:/data # cd /dev
shell@astar-y3:/dev # ll
crw------- root     root     254,   0 1970-01-01 08:03 rtc0
crw-rw---- keystore keystore  10, 111 1970-01-01 08:03 scdev
drwxr-xr-x root     root              1970-01-01 08:03 snd
drwxr-xr-x root     root              1970-01-02 08:05 socket
crw------- root     root     153,   0 1970-01-02 08:07 spidev0.0
crw------- root     root      10,  60 1970-01-01 08:03 sunxi-reg
crw------- root     root     252,   0 1970-01-01 08:03 sunxi_pwm
crw------- root     root      10,  58 1970-01-01 08:03 sw_sync
crw-rw-rw- root     root       5,   0 1970-01-01 08:03 tty


久违了,spidev0.0这个设备节点终于出现了。(/dev/spidev0.0,SINA33平台)




结论:基本上可以肯定是 spi 设备驱动没有加载完全,不让生成 /dev/spidev0.0 这个设备节点。


这个问题可以算是临时解决了。不可能每次系统启动的时候都是手工加载spidev.ko这个模块文件的!
今后肯定要加载到 init.rc里了。还有就是最好直接编进内核了!








对于 cubieboard2平台:


rootroot@rootroot-E400:~/wyb/cubieboard2_sdk_20140508/lichee/linux-3.4$ make ARCH=arm menuconfig


Device Drivers --->
[*] SPI support --->
--- SPI support
[*]   Debug support for SPI drivers
     *** SPI Master Controller Drivers ***
< >   Altera SPI Controller
-*-   Utilities for Bitbanging SPI masters
<*>   GPIO-based bitbanging SPI Master
< >   OpenCores tiny SPI
< >   ARM AMBA PL022 SSP controller
<*>   SUN7I SPI Controller
[*]     SUN7I SPI Normal DMA mode select
[*]     SUN7I SPI Norflash
< >   Xilinx SPI controller common module
<*>   DesignWare SPI controller core support
<*>     Memory-mapped io interface driver for DW SPI core
     *** SPI Protocol Masters ***
<*>   User mode SPI device driver support
< >   Infineon TLE62X0 (for power switching)


这样配置生成节点:/dev/spidev2.0(奇怪不是 /dev/spidev0.0)


Z:\wyb\cubieboard2_sdk_20140508\lichee\tools\pack\chips\sun7i\configs\android\sugar-cubieboard2\sys_config.fex
; gpio的描述形式:Port:端口+组内序号<功能分配><内部电阻状态><驱动能力><输出电平状态>
;           例如:port:PA0<0><default><default><default>
;-------------------------------------------------------------------------------
;spi configuration
;-------------------------------------------------------------------------------


[spi0_para]
spi_used            = 1
spi_cs_bitmap       = 1
spi_cs0             = port:PI10<2><default><default><default>
spi_sclk            = port:PI11<2><default><default><default>
spi_mosi            = port:PI12<2><default><default><default>
spi_miso            = port:PI13<2><default><default><default>




[spi_devices]
spi_dev_num = 1


[spi_board0]
modalias = "spidev"
max_speed_hz = 12000000
bus_num = 0
chip_select = 0
mode = 3
full_duplex = 0

manual_cs = 0





模块的Makefile(SINA33平台):

#
# spidev drivers
#
PWD :=$(shell pwd)
KERNELDIR := /home/rootroot/wyb/sina33/lichee/linux-3.4
ANDROIDDIR := /home/rootroot/wyb/sina33/android


ARCH=arm


CROSS_COMPILE = $(ANDROIDDIR)/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-


CC=$(CROSS_COMPILE)gcc


LD=$(CROSS_COMPILE)ld


obj-m += spidev.o


modules:
$(MAKE) -C $(KERNELDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modules

clean:    
make -C $(KERNELDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) clean





spidev.c

/*
 * Simple synchronous userspace interface to SPI devices
 *
 * Copyright (C) 2006 SWAPP
 * Andrea Paterniani <a.paterniani@swapp-eng.it>
 * Copyright (C) 2007 David Brownell (simplification, cleanup)
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#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/compat.h>


#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>


#include <asm/uaccess.h>




/*
 * This supports access to SPI devices using normal userspace I/O calls.
 * Note that while traditional UNIX/POSIX I/O semantics are half duplex,
 * and often mask message boundaries, full SPI support requires full duplex
 * transfers.  There are several kinds of internal message boundaries to
 * handle chipselect management and other protocol options.
 *
 * SPI has a character major number assigned.  We allocate minor numbers
 * dynamically using a bitmask.  You must use hotplug tools, such as udev
 * (or mdev with busybox) to create and destroy the /dev/spidevB.C device
 * nodes, since there is no fixed association of minor numbers with any
 * particular SPI bus or device.
 */
#define SPIDEV_MAJOR 153/* assigned */
#define N_SPI_MINORS 32/* ... up to 256 */


static DECLARE_BITMAP(minors, N_SPI_MINORS);




/* Bit masks for spi_device.mode management.  Note that incorrect
 * settings for some settings can cause *lots* of trouble for other
 * devices on a shared bus:
 *
 *  - CS_HIGH ... this device will be active when it shouldn't be
 *  - 3WIRE ... when active, it won't behave as it should
 *  - NO_CS ... there will be no explicit message boundaries; this
 * is completely incompatible with the shared bus model
 *  - READY ... transfers may proceed when they shouldn't.
 *
 * REVISIT should changing those flags be privileged?
 */
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
| SPI_NO_CS | SPI_READY)


struct spidev_data {
dev_t devt;
spinlock_t spi_lock;
struct spi_device*spi;
struct list_headdevice_entry;


/* buffer is NULL unless this device is open (users > 0) */
struct mutex buf_lock;
unsigned users;
u8 *buffer;
};


static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);


static unsigned bufsiz = 4096;
module_param(bufsiz, uint, S_IRUGO);
MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");


/*-------------------------------------------------------------------------*/


/*
 * We can't use the standard synchronous wrappers for file I/O; we
 * need to protect against async removal of the underlying spi_device.
 */
static void spidev_complete(void *arg)
{
printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

complete(arg);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);
}


static ssize_t
spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


message->complete = spidev_complete;
message->context = &done;


spin_lock_irq(&spidev->spi_lock);
if (spidev->spi == NULL)
status = -ESHUTDOWN;
else
status = spi_async(spidev->spi, message);
spin_unlock_irq(&spidev->spi_lock);


if (status == 0) {
wait_for_completion(&done);
status = message->status;
if (status == 0)
status = message->actual_length;
}

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

return status;
}


static inline ssize_t
spidev_sync_write(struct spidev_data *spidev, size_t len)
{
struct spi_transfert = {
.tx_buf = spidev->buffer,
.len = len,
};
struct spi_messagem;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


spi_message_init(&m);
spi_message_add_tail(&t, &m);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

return spidev_sync(spidev, &m);
}


static inline ssize_t
spidev_sync_read(struct spidev_data *spidev, size_t len)
{
struct spi_transfert = {
.rx_buf = spidev->buffer,
.len = len,
};
struct spi_messagem;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


spi_message_init(&m);
spi_message_add_tail(&t, &m);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

return spidev_sync(spidev, &m);
}


/*-------------------------------------------------------------------------*/


/* Read-only message with current device setup */
static ssize_t
spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct spidev_data*spidev;
ssize_t status = 0;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


/* chipselect only toggles at start or end of operation */
if (count > bufsiz)
return -EMSGSIZE;


spidev = filp->private_data;


mutex_lock(&spidev->buf_lock);
status = spidev_sync_read(spidev, count);
if (status > 0) {
unsigned long missing;


missing = copy_to_user(buf, spidev->buffer, status);
if (missing == status)
status = -EFAULT;
else
status = status - missing;
}
mutex_unlock(&spidev->buf_lock);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


return status;
}


/* Write-only message with current device setup */
static ssize_t
spidev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
struct spidev_data*spidev;
ssize_t status = 0;
unsigned long missing;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


/* chipselect only toggles at start or end of operation */
if (count > bufsiz)
return -EMSGSIZE;


spidev = filp->private_data;


mutex_lock(&spidev->buf_lock);
missing = copy_from_user(spidev->buffer, buf, count);
if (missing == 0) {
status = spidev_sync_write(spidev, count);
} else
status = -EFAULT;
mutex_unlock(&spidev->buf_lock);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


return status;
}


static int spidev_message(struct spidev_data *spidev,
struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
{
struct spi_messagemsg;
struct spi_transfer*k_xfers;
struct spi_transfer*k_tmp;
struct spi_ioc_transfer *u_tmp;
unsigned n, total;
u8 *buf;
int status = -EFAULT;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


spi_message_init(&msg);
k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
if (k_xfers == NULL)
return -ENOMEM;


/* Construct spi_message, copying any tx data to bounce buffer.
* We walk the array of user-provided transfers, using each one
* to initialize a kernel version of the same transfer.
*/
buf = spidev->buffer;
total = 0;
for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
n;
n--, k_tmp++, u_tmp++) {
k_tmp->len = u_tmp->len;


total += k_tmp->len;
if (total > bufsiz) {
status = -EMSGSIZE;
goto done;
}


if (u_tmp->rx_buf) {
k_tmp->rx_buf = buf;
if (!access_ok(VERIFY_WRITE, (u8 __user *)
(uintptr_t) u_tmp->rx_buf,
u_tmp->len))
goto done;
}
if (u_tmp->tx_buf) {
k_tmp->tx_buf = buf;
if (copy_from_user(buf, (const u8 __user *)
(uintptr_t) u_tmp->tx_buf,
u_tmp->len))
goto done;
}
buf += k_tmp->len;


k_tmp->cs_change = !!u_tmp->cs_change;
k_tmp->bits_per_word = u_tmp->bits_per_word;
k_tmp->delay_usecs = u_tmp->delay_usecs;
k_tmp->speed_hz = u_tmp->speed_hz;
#ifdef VERBOSE
dev_dbg(&spidev->spi->dev,
"  xfer len %zd %s%s%s%dbits %u usec %uHz\n",
u_tmp->len,
u_tmp->rx_buf ? "rx " : "",
u_tmp->tx_buf ? "tx " : "",
u_tmp->cs_change ? "cs " : "",
u_tmp->bits_per_word ? : spidev->spi->bits_per_word,
u_tmp->delay_usecs,
u_tmp->speed_hz ? : spidev->spi->max_speed_hz);
#endif
spi_message_add_tail(k_tmp, &msg);
}


status = spidev_sync(spidev, &msg);
if (status < 0)
goto done;


/* copy any rx data out of bounce buffer */
buf = spidev->buffer;
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
if (u_tmp->rx_buf) {
if (__copy_to_user((u8 __user *)
(uintptr_t) u_tmp->rx_buf, buf,
u_tmp->len)) {
status = -EFAULT;
goto done;
}
}
buf += u_tmp->len;
}
status = total;


done:
kfree(k_xfers);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

return status;
}


static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int err = 0;
int retval = 0;
struct spidev_data*spidev;
struct spi_device*spi;
u32 tmp;
unsigned n_ioc;
struct spi_ioc_transfer*ioc;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


/* Check type and command number */
if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
return -ENOTTY;


/* Check access direction once here; don't repeat below.
* IOC_DIR is from the user perspective, while access_ok is
* from the kernel perspective; so they look reversed.
*/
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)
return -EFAULT;


/* guard against device removal before, or while,
* we issue this ioctl.
*/
spidev = filp->private_data;
spin_lock_irq(&spidev->spi_lock);
spi = spi_dev_get(spidev->spi);
spin_unlock_irq(&spidev->spi_lock);


if (spi == NULL)
return -ESHUTDOWN;


/* use the buffer lock here for triple duty:
*  - prevent I/O (from us) so calling spi_setup() is safe;
*  - prevent concurrent SPI_IOC_WR_* from morphing
*    data fields while SPI_IOC_RD_* reads them;
*  - SPI_IOC_MESSAGE needs the buffer locked "normally".
*/
mutex_lock(&spidev->buf_lock);


switch (cmd) {
/* read requests */
case SPI_IOC_RD_MODE:
retval = __put_user(spi->mode & SPI_MODE_MASK,
(__u8 __user *)arg);
break;
case SPI_IOC_RD_LSB_FIRST:
retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,
(__u8 __user *)arg);
break;
case SPI_IOC_RD_BITS_PER_WORD:
retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);
break;
case SPI_IOC_RD_MAX_SPEED_HZ:
retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
break;


/* write requests */
case SPI_IOC_WR_MODE:
retval = __get_user(tmp, (u8 __user *)arg);
if (retval == 0) {
u8 save = spi->mode;


if (tmp & ~SPI_MODE_MASK) {
retval = -EINVAL;
break;
}


tmp |= spi->mode & ~SPI_MODE_MASK;
spi->mode = (u8)tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->mode = save;
else
dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
}
break;
case SPI_IOC_WR_LSB_FIRST:
retval = __get_user(tmp, (__u8 __user *)arg);
if (retval == 0) {
u8 save = spi->mode;


if (tmp)
spi->mode |= SPI_LSB_FIRST;
else
spi->mode &= ~SPI_LSB_FIRST;
retval = spi_setup(spi);
if (retval < 0)
spi->mode = save;
else
dev_dbg(&spi->dev, "%csb first\n",
tmp ? 'l' : 'm');
}
break;
case SPI_IOC_WR_BITS_PER_WORD:
retval = __get_user(tmp, (__u8 __user *)arg);
if (retval == 0) {
u8 save = spi->bits_per_word;


spi->bits_per_word = tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->bits_per_word = save;
else
dev_dbg(&spi->dev, "%d bits per word\n", tmp);
}
break;
case SPI_IOC_WR_MAX_SPEED_HZ:
retval = __get_user(tmp, (__u32 __user *)arg);
if (retval == 0) {
u32 save = spi->max_speed_hz;


spi->max_speed_hz = tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->max_speed_hz = save;
else
dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
}
break;


default:
/* segmented and/or full-duplex I/O request */
if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
|| _IOC_DIR(cmd) != _IOC_WRITE) {
retval = -ENOTTY;
break;
}


tmp = _IOC_SIZE(cmd);
if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
retval = -EINVAL;
break;
}
n_ioc = tmp / sizeof(struct spi_ioc_transfer);
if (n_ioc == 0)
break;


/* copy into scratch area */
ioc = kmalloc(tmp, GFP_KERNEL);
if (!ioc) {
retval = -ENOMEM;
break;
}
if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
kfree(ioc);
retval = -EFAULT;
break;
}


/* translate to spi_message, execute */
retval = spidev_message(spidev, ioc, n_ioc);
kfree(ioc);
break;
}


mutex_unlock(&spidev->buf_lock);
spi_dev_put(spi);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

return retval;
}


#ifdef CONFIG_COMPAT
static long
spidev_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
return spidev_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
}
#else
#define spidev_compat_ioctl NULL
#endif /* CONFIG_COMPAT */


static int spidev_open(struct inode *inode, struct file *filp)
{
struct spidev_data*spidev;
int status = -ENXIO;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


mutex_lock(&device_list_lock);


list_for_each_entry(spidev, &device_list, device_entry) {
if (spidev->devt == inode->i_rdev) {
status = 0;
break;
}
}
if (status == 0) {
if (!spidev->buffer) {
spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
if (!spidev->buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
status = -ENOMEM;
}
}
if (status == 0) {
spidev->users++;
filp->private_data = spidev;
nonseekable_open(inode, filp);
}
} else
pr_debug("spidev: nothing for minor %d\n", iminor(inode));


mutex_unlock(&device_list_lock);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

return status;
}


static int spidev_release(struct inode *inode, struct file *filp)
{
struct spidev_data*spidev;
int status = 0;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


mutex_lock(&device_list_lock);
spidev = filp->private_data;
filp->private_data = NULL;


/* last close? */
spidev->users--;
if (!spidev->users) {
int dofree;


kfree(spidev->buffer);
spidev->buffer = NULL;


/* ... after we unbound from the underlying device? */
spin_lock_irq(&spidev->spi_lock);
dofree = (spidev->spi == NULL);
spin_unlock_irq(&spidev->spi_lock);


if (dofree)
kfree(spidev);
}
mutex_unlock(&device_list_lock);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


return status;
}


static const struct file_operations spidev_fops = {
.owner = THIS_MODULE,
/* REVISIT switch to aio primitives, so that userspace
* gets more complete API coverage.  It'll simplify things
* too, except for the locking.
*/
.write = spidev_write,
.read = spidev_read,
.unlocked_ioctl = spidev_ioctl,
.compat_ioctl = spidev_compat_ioctl,
.open = spidev_open,
.release = spidev_release,
.llseek = no_llseek,
};


/*-------------------------------------------------------------------------*/


/* The main reason to have this class is to make mdev/udev create the
 * /dev/spidevB.C character device nodes exposing our userspace API.
 * It also simplifies memory management.
 */


static struct class *spidev_class;


/*-------------------------------------------------------------------------*/


static int __devinit spidev_probe(struct spi_device *spi)
{
struct spidev_data*spidev;
int status;
unsigned long minor;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


/* Allocate driver data */
spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
if (!spidev)
return -ENOMEM;


/* Initialize the driver data */
spidev->spi = spi;
spin_lock_init(&spidev->spi_lock);
mutex_init(&spidev->buf_lock);


INIT_LIST_HEAD(&spidev->device_entry);


/* If we can allocate a minor number, hook up this device.
* Reusing minors is fine so long as udev or mdev is working.
*/
mutex_lock(&device_list_lock);
minor = find_first_zero_bit(minors, N_SPI_MINORS);
if (minor < N_SPI_MINORS) {
struct device *dev;


spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
dev = device_create(spidev_class, &spi->dev, spidev->devt,
   spidev, "spidev%d.%d",
   spi->master->bus_num, spi->chip_select);
status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
} else {
dev_dbg(&spi->dev, "no minor number available!\n");
status = -ENODEV;
}
if (status == 0) {
set_bit(minor, minors);
list_add(&spidev->device_entry, &device_list);
}
mutex_unlock(&device_list_lock);


if (status == 0)
spi_set_drvdata(spi, spidev);
else
kfree(spidev);


printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

return status;
}


static int __devexit spidev_remove(struct spi_device *spi)
{
struct spidev_data*spidev = spi_get_drvdata(spi);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


/* make sure ops on existing fds can abort cleanly */
spin_lock_irq(&spidev->spi_lock);
spidev->spi = NULL;
spi_set_drvdata(spi, NULL);
spin_unlock_irq(&spidev->spi_lock);


/* prevent new opens */
mutex_lock(&device_list_lock);
list_del(&spidev->device_entry);
device_destroy(spidev_class, spidev->devt);
clear_bit(MINOR(spidev->devt), minors);
if (spidev->users == 0)
kfree(spidev);
mutex_unlock(&device_list_lock);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


return 0;
}


static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "spidev",
.owner = THIS_MODULE,
},
.probe = spidev_probe,
.remove = __devexit_p(spidev_remove),


/* NOTE:  suspend/resume methods are not necessary here.
* We don't do anything except pass the requests to/from
* the underlying controller.  The refrigerator handles
* most issues; the controller driver handles the rest.
*/
};


/*-------------------------------------------------------------------------*/


static int __init spidev_init(void)
{
int status;

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);


/* Claim our 256 reserved device numbers.  Then register a class
* that will key udev/mdev to add/remove /dev nodes.  Last, register
* the driver which manages those device numbers.
*/
BUILD_BUG_ON(N_SPI_MINORS > 256);
status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
if (status < 0)
return status;


spidev_class = class_create(THIS_MODULE, "spidev");
if (IS_ERR(spidev_class)) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
return PTR_ERR(spidev_class);
}


status = spi_register_driver(&spidev_spi_driver);
if (status < 0) {
class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
}

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

return status;
}
module_init(spidev_init);


static void __exit spidev_exit(void)
{
printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);

spi_unregister_driver(&spidev_spi_driver);
class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);

printk("****wyb %s:%d/%s()!\n", __FILE__, __LINE__, __func__);
}
module_exit(spidev_exit);


MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
MODULE_DESCRIPTION("User mode SPI device interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:spidev");


改动的文件(带目录结构)的下载链接:
http://download.csdn.net/detail/wb4916/8789897
sina33备份的文件20150609_2100.7z



  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 全志A33全志科技推出的一款低功耗、高性能的32位ARM Cortex-A7处理器,适用于智能穿戴设备、智能音箱、平板电脑等场景。Debian是一种常用的Linux操作系统,具有丰富的应用程序和强大的系统设置。全志A33 Debian固件就是将Debian操作系统移植到全志A33处理器上的一种固件,能够将全志A33处理器变成一台类似于电脑的设备。 使用全志A33 Debian固件可以实现如下功能: 1.运行普通PC上的应用程序 2.连接外部设备,如键盘、鼠标、外置硬盘等 3.使用缺省的GNOME桌面环境,支持多任务和多用户功能 4.支持浏览器、邮件客户端、媒体播放器等应用程序 5.通过SSH协议进行远程登录和管理 6.充分利用全志A33的性能,提供比其他嵌入式解决方案更好的用户体验。 总之,全志A33 Debian固件可以大大提高全志A33处理器的实用性和灵活性,使用户可以在嵌入式系统中获得更多的多媒体、游戏、互联网等方面的体验。 ### 回答2: 全志a33处理器是一款广泛应用于智能电视、平板电脑、智能家居等领域的芯片,它采用ARM Cortex A7结构设计,能够提供快速稳定的性能表现。而Debian固件则是为这种处理器开发的一种系统镜像,它基于Debian操作系统开发,兼具稳定性和开放性。 Debian固件的开源性和普适性让其成为软件开发者的首选,这个系统可以让用户享受到更多的开发自由度和DIY空间。而全志a33芯片的流行,也带来了对其能否支持Debian固件的讨论。经过不断的努力,目前已经可以使用全志a33 Debian固件来打造更高效的智能设备了。 使用全志a33 Debian固件,用户可以利用安装包管理器和便捷的命令行方式来自由控制系统,开发维护更加灵活自在。此外,全志a33 Debian固件也内置了大量的软件库和应用支持,帮助开发人员快速构建想要的功能。这种固件还支持多系统同时运行,方便用户在一个设备上运行不同版本的应用程序,提升了设备的效率和兼容性。 综上所述,全志a33 Debian固件是一种功能齐全、兼具可靠性和自由性的系统,众多开发者和用户都对其有很高的期望。相信随着技术和市场的不断变化,这种固件也将会展现更加出色的表现。 ### 回答3: 全志A33是一款低功耗、高性能的ARM Cortex-A7处理器,广泛用于平板电脑、智能家居、智能设备等领域。其中,Debian固件指的是以Debian Linux作为基础系统的固件。 全志A33 Debian固件的优势在于可以利用Debian社区的广泛资源和软件包,为用户提供更加丰富和稳定的软件支持。此外,Debian固件还可以定制化,用户可以根据实际需求选择安装所需要的软件和服务,而不必依赖于预装软件包。 但是,全志A33 Debian固件也存在一些不足之处。首先,由于Debian系统的安全性要求较高,因此对硬件的要求也相应升高,需要支持的硬件也较多,这可能会导致部分硬件不兼容而无法使用。其次,Debian固件相对于定制化的固件来说,开发难度和复杂度都较高,对开发者的技术水平和精力要求也较高。 综上所述,全志A33 Debian固件相对于其他定制化固件来说,拥有更加丰富和稳定的软件支持和更多的可定制化功能,同时也存在一些不足之处需要用户和开发者注意。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值