링크 ux SPI 구동 프레임 워 크(2)--장치 구동
이전 글 Liux SPI 구동 프레임 워 크(1)-컨트롤 러 구동http://blog.csdn.net/flaoter/article/details/50001133이 절 은 SPI 가 장치 의 장치 구동 에서 설명 하 는 내용 을 소개 합 니 다.
장치 구동 이 주목 하 는 구조 체 는 주로 두 가지 가 있 습 니 다.struct spidevice 설명 spi 장치,struct spidriver 는 장치 의 장치 에서 구동 된다.
struct spi_device {
struct device dev;
struct spi_master *master;
u32 max_speed_hz;
u8 chip_select;
u8 bits_per_word;
u16 mode;
#define SPI_CPHA 0x01 /* clock phase */
#define SPI_CPOL 0x02 /* clock polarity */
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04 /* chipselect active high? */
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
#define SPI_3WIRE 0x10 /* SI/SO signals shared */
#define SPI_LOOP 0x20 /* loopback mode */
#define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */
#define SPI_READY 0x80 /* slave pulls low to pause */
#define SPI_TX_DUAL 0x100 /* transmit with 2 wires */
#define SPI_TX_QUAD 0x200 /* transmit with 4 wires */
#define SPI_RX_DUAL 0x400 /* receive with 2 wires */
#define SPI_RX_QUAD 0x800 /* receive with 4 wires */
int irq;
void *controller_state;
void *controller_data;
char modalias[SPI_NAME_SIZE];
int cs_gpio; /* chip select gpio */
/*
* likely need more hooks for more protocol options affecting how
* the controller talks to each chip, like:
* - memory packing (12 bit samples into low bits, others zeroed)
* - priority
* - drop chipselect after each word
* - chipselect delays
* - ...
*/
};
struct spi_driver {
const struct spi_device_id *id_table;
int (*probe)(struct spi_device *spi);
int (*remove)(struct spi_device *spi);
void (*shutdown)(struct spi_device *spi);
int (*suspend)(struct spi_device *spi, pm_message_t mesg);
int (*resume)(struct spi_device *spi);
struct device_driver driver;
};
초기 화 함 수 는 다음 과 같 습 니 다.코드 설명 은 코드 설명 을 참조 합 니 다.이 코드 에는 장치 등록 코드 가 포함 되 어 있 지만 dts 가 보편적으로 응 용 된 후에 이 장치 등록 방식 은 장치 트 리 방식 으로 대체 되 었 습 니 다.이곳 의 장치 등록 응용 장면 은 모듈 방식 으로 컴 파일 된 구동 디자인 에 많이 나타 납 니 다.따라서 설비 등록 에 헷 갈 리 지 마 세 요.
static int __init spidev_init(void)
{
int status;
/* 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);
// , SPIDEV_MAJOR, "spi", ops spidev_fops, /proc/devices , udev uevent, /dev ,
status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
if (status < 0)
return status;
// spidev class, /sys/class/spidev
spidev_class = class_create(THIS_MODULE, "spidev");
if (IS_ERR(spidev_class)) {
status = PTR_ERR(spidev_class);
goto error_class;
}
// spidev_spi_driver
status = spi_register_driver(&spidev_spi_driver);
if (status < 0)
goto error_register;
// , module driver ,busnum, chipselect MODULE_PARAM ;
// , spi_master , dts spi slave spi_device
if (busnum != -1 && chipselect != -1) {
struct spi_board_info chip = {
.modalias = "spidev", // device_driver match
.mode = spimode, //spi
.bus_num = busnum, //spi master busnum
.chip_select = chipselect,
.max_speed_hz = maxspeed,
};
struct spi_master *master;
master = spi_busnum_to_master(busnum); // busnum spi_master
if (!master) {
status = -ENODEV;
goto error_busnum;
}
//spi slave spi_device , master slave
/* We create a virtual device that will sit on the bus */
spi = spi_new_device(master, &chip);
if (!spi) {
status = -EBUSY;
goto error_mem;
}
dev_dbg(&spi->dev, "busnum=%d cs=%d bufsiz=%d maxspeed=%d",
busnum, chipselect, bufsiz, maxspeed);
}
return 0;
error_mem:
error_busnum:
spi_unregister_driver(&spidev_spi_driver);
error_register:
class_destroy(spidev_class);
error_class:
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
return status;
}
module_init(spidev_init);
다음은 장치 구동 의 정의 입 니 다.compatible 이 장치 등록 속성 과 일치 할 때 spidevprobe 호출 됩 니 다.
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "rohm,dh2228fv", },
{ .compatible = "qcom,spi-msm-codec-slave", },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "spidev",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(spidev_dt_ids),
},
.probe = spidev_probe,
.remove = 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.
*/
};
probe 함수 정 의 는 다음 과 같 습 니 다.
static int spidev_probe(struct spi_device *spi)
{
struct spidev_data *spidev;
int status;
unsigned long minor;
/* 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);
// ,/sys/class/spidev spidev%d.%d , udev /dev
dev = device_create(spidev_class, &spi->dev, spidev->devt,
spidev, "spidev%d.%d",
spi->master->bus_num, spi->chip_select);
status = PTR_ERR_OR_ZERO(dev);
} else {
dev_dbg(&spi->dev, "no minor number available!
");
status = -ENODEV;
}
if (status == 0) {
set_bit(minor, minors);
list_add(&spidev->device_entry, &device_list); // spidev device_list
}
mutex_unlock(&device_list_lock);
if (status == 0)
spi_set_drvdata(spi, spidev); //spi->dev->drvdata=spidev
else
kfree(spidev);
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,
};
다음은 open 과 write 함 수 를 예 로 들 어 장치 조작 함수 에 대해 설명 합 니 다.
static int spidev_open(struct inode *inode, struct file *filp)
{
struct spidev_data *spidev;
int status = -ENXIO;
mutex_lock(&device_list_lock);
list_for_each_entry(spidev, &device_list, device_entry) { // inode->i_rdev device_list spidev
if (spidev->devt == inode->i_rdev) {
status = 0;
break;
}
}
if (status) {
pr_debug("spidev: nothing for minor %d
", iminor(inode));
goto err_find_dev;
}
if (!spidev->tx_buffer) {
spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL); // tx buffer
if (!spidev->tx_buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM
");
status = -ENOMEM;
goto err_find_dev;
}
}
if (!spidev->rx_buffer) {
spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL); // rx buffer
if (!spidev->rx_buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM
");
status = -ENOMEM;
goto err_alloc_rx_buf;
}
}
spidev->users++; //
filp->private_data = spidev; // spidev filp
nonseekable_open(inode, filp);
mutex_unlock(&device_list_lock);
return 0;
err_alloc_rx_buf:
kfree(spidev->tx_buffer);
spidev->tx_buffer = NULL;
err_find_dev:
mutex_unlock(&device_list_lock);
return status;
}
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;
/* chipselect only toggles at start or end of operation */
if (count > bufsiz)
return -EMSGSIZE;
spidev = filp->private_data; // filp spidev
mutex_lock(&spidev->buf_lock);
missing = copy_from_user(spidev->tx_buffer, buf, count); // buf spidev->tx_buf
if (missing == 0)
status = spidev_sync_write(spidev, count); // spidev_sync_write
else
status = -EFAULT;
mutex_unlock(&spidev->buf_lock);
return status;
}
write 함수 의 구체 적 인 실현 은 다음 과 같 습 니 다.
static inline ssize_t
spidev_sync_write(struct spidev_data *spidev, size_t len)
{
struct spi_transfer t = {
.tx_buf = spidev->tx_buffer,
.len = len,
};
struct spi_message m;
spi_message_init(&m); // spi_message
spi_message_add_tail(&t, &m); // spi_transfer spi_message
return spidev_sync(spidev, &m); // spidev_sync
}
static ssize_t
spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;
message->complete = spidev_complete;
message->context = &done; //spi_message
spin_lock_irq(&spidev->spi_lock);
if (spidev->spi == NULL)
status = -ESHUTDOWN;
else
status = spi_async(spidev->spi, message); // spi_async
spin_unlock_irq(&spidev->spi_lock);
if (status == 0) {
wait_for_completion(&done); //
status = message->status;
if (status == 0)
status = message->actual_length;
}
return status;
}
int spi_async(struct spi_device *spi, struct spi_message *message)
{
struct spi_master *master = spi->master;
int ret;
unsigned long flags;
ret = __spi_validate(spi, message);
if (ret != 0)
return ret;
spin_lock_irqsave(&master->bus_lock_spinlock, flags);
if (master->bus_lock_flag)
ret = -EBUSY;
else
ret = __spi_async(spi, message); // __spi_async
spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
return ret;
}
static int __spi_async(struct spi_device *spi, struct spi_message *message)
{
struct spi_master *master = spi->master; // master
message->spi = spi; //spi_message
trace_spi_message_submit(message);
return master->transfer(spi, message); // master->transfer
}
transfer 함수 의 실현 은 컨트롤 러 구동 장 에서 상세 한 설명 이 있 으 며,이 곳 에 서 는 중복 되 지 않 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
용감한 바로 가기 및 우분투 응용 프로그램안녕하세요 여러분, 이 기사에서는 모든 사이트에서 pwa를 생성하고 실행기 응용 프로그램으로 추가하는 방법을 설명하고 싶습니다. 일부 웹사이트는 PWA로 설치를 허용하지 않지만 유사한 애플리케이션을 원합니다. 1. ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.