Linux设备驱动器 之二 线程同步第二篇
mutex
数据结构
struct mutex {
atomic_long_t owner;
raw_spinlock_t wait_lock;
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
struct optimistic_spin_queue osq; /* Spinner MCS lock */
#endif
struct list_head wait_list;
#ifdef CONFIG_DEBUG_MUTEXES
void *magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
};
Linux APIs
void mutex_init(struct mutex *lock);
bool mutex_is_locked(struct mutex *lock);
void mutex_lock(struct mutex *lock);
int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
int mutex_trylock(struct mutex *lock);
void mutex_unlock(struct mutex *lock);
在Linux驱动器中的应用
NXP freescale系列QSPI 驱动器
变量定义
struct fsl_qspi {
...
struct mutex lock;
...
};
初始化
static int fsl_qspi_probe(struct platform_device *pdev) {
...
mutex_init(&q->lock);
...
}
存取数据
如果有大块数据,使用AHB总线,通过存取映射的存储器,存取数据。
static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
...
mutex_lock(&q->lock);
...
fsl_qspi_prepare_lut(q, op);
/*
* If we have large chunks of data, we read them through the AHB bus
* by accessing the mapped memory. In all other cases we use
* IP commands to access the flash.
*/
if (op->data.nbytes > (q->devtype_data->rxfifo - 4) &&
op->data.dir == SPI_MEM_DATA_IN) {
fsl_qspi_read_ahb(q, op);
} else {
qspi_writel(q, QUADSPI_RBCT_WMRK_MASK |
QUADSPI_RBCT_RXBRD_USEIPS, base + QUADSPI_RBCT);
if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
fsl_qspi_fill_txfifo(q, op);
err = fsl_qspi_do_op(q, op);
}
/* Invalidate the data in the AHB buffer. */
fsl_qspi_invalidate(q);
mutex_unlock(&q->lock);
}
semaphore
数据结构
struct semaphore {
raw_spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
Linux APIs
void sema_init(struct semaphore *sem, int val);
void down(struct semaphore *sem);
int down_interruptible(struct semaphore *sem);
int down_trylock(struct semaphore *sem);
int down_timeout(struct semaphore *sem, long jiffies);
void up(struct semaphore *sem);
在Linux驱动器中的应用
ELAN 的 Uxxx 系列驱动器
ELAN 的 Uxxx 系列适配器是 USB 转 PCMCIA CardBus 适配器
变量定义
struct usb_ftdi {
...
struct semaphore sw_lock;
...
};
初始化
static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
{
dev_set_drvdata(&intf->dev, data);
}
static int ftdi_elan_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
...
sema_init(&ftdi->sw_lock, 1);
...
usb_set_intfdata(interface, ftdi);
...
}
usb_set_intfdata将FTDI的驱动器数据写入驱动器的数据结构变量中。在需要的生活可以通过驱动器结构变量存取。
同步操作
static void ftdi_elan_status_work(struct work_struct *work)
{
...
if(ftdi->disconnected > 0){
....
} else if (ftdi->synchronized == 0) {
down(&ftdi->sw_lock);
if (ftdi_elan_synchronize(ftdi) == 0) {
ftdi->synchronized = 1;
ftdi_command_queue_work(ftdi, 1);
ftdi_respond_queue_work(ftdi, 1);
up(&ftdi->sw_lock);
work_delay_in_msec = 100;
} else {
dev_err(&ftdi->udev->dev, "synchronize failed\n");
up(&ftdi->sw_lock);
work_delay_in_msec = 10 *1000;
}
}
...
}
down(&ftdi->sw_lock),up(&ftdi->sw_lock); 保证一个线程进行同步过程。
down(&ftdi->sw_lock) 让当前线程拥有这个semaphore,其他线程无法再次进入同步过程。在同步过程完成后,当前线程释放semaphore。