10-1ADC驱动程序

10-1-1 说明

程序源代码说明:

驱动源代码所在目录

drivers/spi/

驱动程序名称

mcp3201.c

设备号

mcp3201属于杂项设备,设备自动生成

设备名

/dev/mcp3201

测试程序源代码目录

Examples/Drivers/ADC

测试程序名称

test-mcp3201.c

测试程序可执行文件名称

test-mcp3201

要写实际的驱动,就必须了解相关的硬件资源,比如用到的寄存器,物理地址,中断等,在这里,mcp3201是一个很简单的例子,它用到了如下硬件资源。

开发板上所用到的 1个ADC的硬件资源:

ADC

对应的IO 寄存器名称

对应的CPU 引脚

Mcp3201

Spi0

G16

要操作所用到的 IO口,就要设置它们所用到的寄存器,我们可以调用一些现成的函数或者宏,在我们的驱动中使用的是mcp3201_open()来进行控制的。

函数mcp3201_open()的定义在我们的驱动程序中,接下来的驱动程序代码将给出示意。

在下面的驱动代码中,你将看到调用mcp3201_open()函数来对设备实施初始化并打开,除此之外,还需要调用一些和设备驱动密切相关的基本函数,如注册设备misc_register,填写驱动函数结构file_operations,以及像Hello,Module中那样的module_init和module_exit函数等。

有些函数并不是必须的,随着你对Linux驱动开发的进一步了解和的代码,你自然明白。下面是我们为mcp3201编写的驱动代码清单。

10-1-2驱动程序清单

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#defineSB2F_BOARD_SPI0_BASE0xbfe80000

struct spi_device *adc;

static int mcp3201_open(struct inode *inode, struct file *file) {

//取消片选CS3

writeb(0xff, SB2F_BOARD_SPI0_BASE + REG_SPCSR);

//复位SPI控制寄存器工作

writeb(0x10, SB2F_BOARD_SPI0_BASE + REG_SPCR);

//重置状态寄存器SPSR

writeb(0xc0, SB2F_BOARD_SPI0_BASE + REG_SPSR);

//设置外部寄存器

writeb(0x02, SB2F_BOARD_SPI0_BASE + REG_SPER);

//禁用SPI FLASH读

writeb(0x30, SB2F_BOARD_SPI0_BASE + REG_SPPR);

//配置SPI时序

writeb(0xd3, SB2F_BOARD_SPI0_BASE + REG_SPCR);

//设置片选CS3

writeb(0x7f, SB2F_BOARD_SPI0_BASE + REG_SPCSR);

return 0;

}

static int mcp3201_close(struct inode *inode, struct file *file) {

//取消对CS3的片选

writeb(0xff, SB2F_BOARD_SPI0_BASE + REG_SPCSR);

return 0;

}

static ssize_t mcp3201_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)

{

ssize_t retval;

unsigned char val[2] = {0x0};

unsigned char tx_buf[1] = {0x0};

unsigned char rx_buf[2] = {0};

//发送0个字节的命令到spi从机,并从spi从机中读取2字节的数据到缓冲区

retval = spi_write_then_read(adc, tx_buf, 0, rx_buf, 2);

if (retval

dev_err(&adc->dev, "error %d reading SR\n", (int)retval);

return retval;

}

//对从mcp3201读来的数据,按照其datasheet的要求取出编码

val[0] = rx_buf[1] >> 1;

val[0] |= (rx_buf[0] & 0x01) <

val[1] = (rx_buf[0] >> 1) & 0xf;

//将从mcp3201取出的数据合理编码,并传送到用户空间供用户使用

if (copy_to_user(buf, val, 2))

{

printk("Copy data to userspace error!\n");

return -EFAULT;

}

return 0;

}

static int __devinit mcp3201_probe(struct spi_device *spi)

{

struct spi_device *spi0;

spi0 = spi;

adc = spi0;

return 0;

}

static int __devexit mcp3201_remove(struct spi_device *spi)

{

writeb(0xff, SB2F_BOARD_SPI0_BASE + REG_SPCSR);

return 0;

}

static struct spi_driver mcp3201_driver = {

.driver = {

.name= "mcp3201",

.bus= &spi_bus_type,

.owner= THIS_MODULE,

},

.probe= mcp3201_probe,

.remove= __devexit_p(mcp3201_remove),

};

static const struct file_operations mcp3201_ops = {

.owner = THIS_MODULE,

.open = mcp3201_open,

.release = mcp3201_close,

.read = mcp3201_read,

};

static struct miscdevice mcp3201_miscdev = {

MISC_DYNAMIC_MINOR,

"mcp3201",

&mcp3201_ops,

};

static int mcp3201_init(void)

{

if (misc_register(&mcp3201_miscdev)) {

printk(KERN_WARNING "buzzer:Couldn't register device 10, %d.\n", 255);

return -EBUSY;

}

return spi_register_driver(&mcp3201_driver);

}

static void mcp3201_exit(void)

{

spi_unregister_driver(&mcp3201_driver);

}

module_init(mcp3201_init);

module_exit(mcp3201_exit);

MODULE_LICENSE("GPL");

10-2外部按键驱动

10-2-1 说明

程序源代码说明:

驱动源程序所在目录

driver/input/

驱动程序名

74LV165_button.c

74LV165_button.h

设备名

ls1b_buttons

测试程序源代码目录

测试程序代码名

74LV165_test.c

测试程序可执行文件名

74LV165_test

说明:按键驱动已经被编译到缺省内核中,因此不用使用insmod方式加载

开发板用到的资源:

gpio0

KEY_DATA

gpio1

KEY_EN

gpio2

KEY_SCL

按键驱动在硬件上没有接外部中断,且通过两片并行输入串行输出的移位芯片74LV165连接,因此,按键通过轮询的方式实现。应用程序直接读取/dev/ls1b_buttons设备节点来对按键值进行读取。在启动linux内核后,在根目录下执行当前目录下的可执行文件74LV165_test。

10-2-2驱动程序清单

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include "74LV165_button.h"

#define BUF_MAXSIZE 16

#define TIMER_DELAY 5

static  unsigned int  BReadBuf = 0;

static  int delay(int time){

while(--time);

return 0;

}

static void prepare_for_read(void){

int reg = 0;

/* CP =0 */

LS1B_74LV165_READ(reg, LS1B_74LV165_CP);

LS1B_74LV165_WRITE(LS1B_74LV165_CP, reg & (~(1 <

/* PL = 0 */

LS1B_74LV165_READ(reg, LS1B_74LV165_PL);

LS1B_74LV165_WRITE(LS1B_74LV165_PL, reg & ~(1 <

/* delay 100 */

delay(10000);

/* PL = 1 */

LS1B_74LV165_READ(reg, LS1B_74LV165_PL);

LS1B_74LV165_WRITE(LS1B_74LV165_PL, reg | (1 <

}

static void scanf_keyboard(void){

int reg = 0, val = 0;

int time;

delay(10);

LS1B_74LV165_READ(reg, LS1B_74LV165_DATA);

val = ((~reg) & (1 <

BReadBuf = val >> 0;

for(time = 1; time

/* delay */

delay(100);

/* CP = 1 */

LS1B_74LV165_READ(reg, LS1B_74LV165_CP);

LS1B_74LV165_WRITE(LS1B_74LV165_CP, reg | (1 <

delay(100);

LS1B_74LV165_READ(reg, LS1B_74LV165_DATA);

val = ((~reg) & (1 <

BReadBuf |= val <

/* CP = 0 */

LS1B_74LV165_READ(reg, LS1B_74LV165_CP);

LS1B_74LV165_WRITE(LS1B_74LV165_CP, reg & (~(1 <

}

}

static  void button_read(void){

prepare_for_read();

/* scanf keyboard */

scanf_keyboard();

if(BReadBuf){

printk("\nBReadBuf value is 0x%08x\n",BReadBuf);

}

}

static  int LS1B_74LV165_button_open(struct inode *inode, struct file *filp){

int reg;

printk("Welcome to use 74LV165 driver\n");

//enalbe pin

LS1B_74LV165_EN_GPIO(GPIO_KEY_DATA);

LS1B_74LV165_EN_GPIO(GPIO_KEY_EN);

LS1B_74LV165_EN_GPIO(GPIO_KEY_SCL);

//enable output

LS1B_74LV165_OEN_GPIO(GPIO_KEY_SCL);

LS1B_74LV165_OEN_GPIO(GPIO_KEY_EN);

LS1B_74LV165_IEN_GPIO(GPIO_KEY_DATA);

printk("init 74LV165 is done\n");

return 0;

}

static  ssize_t LS1B_74LV165_button_read(struct file  *filp, char __user *buf, size_t count, loff_t *oppos){

button_read();

if(BReadBuf){

copy_to_user(buf,&BReadBuf,count);

BReadBuf= 0;

delay(10000000);

return count;

}

return -EFAULT;

}

static int LS1B_74LV165_button_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){

return 0;

}

static  struct file_operations ls1b_74Llv165_button_fops = {

.open = LS1B_74LV165_button_open,

.read = LS1B_74LV165_button_read,

.ioctl = LS1B_74LV165_button_ioctl,

};

static struct miscdevice ls1b_74lv165_button = {

.minor = LS1B_BUTTON_MINOR,

.name  = "ls1b_buttons",

.fops  = &ls1b_74Llv165_button_fops,

};

static  int __init  LS1B_74LV165_button_init(void){

int ret;

printk("======================button init=========================\n");

ret = misc_register(&ls1b_74lv165_button);

if(ret

printk("74LV165_button can't get major number !\n");

return ret;

}

#ifdef CONFIG_DEVFS_FS

devfs_button_dir = devfs_mk_dir(NULL,"LS1B_74LV165_button",NULL);

devfs_buttonraw = devfs_register(devfs_kbd_dir,"0raw",DEVFS_FL_DEFAULT,kbdMajor,KBDRAW_MINOR,S_IFCHR|S_IRUSR|S_IWUSR,&LS1B_74LV165_button_fops,NULL);

#endif

return 0;

}

static  void  __exit  LS1B_74LV165_button_exit(void){

misc_deregister(&ls1b_74lv165_button);

}

module_init(LS1B_74LV165_button_init);

module_exit(LS1B_74LV165_button_exit);

其中module_init()和module_exit()函数注册了LS1B_74LV165_button_init及LS1B_74LV165_button_exit函数。当模块加载时将会调用这两个函数。

在LS1B_74LV165_button_init()函数中调用misc_register()函数注册按键驱动为misc设备。并将struct miscdevice的数据结构传递给该函数,在该结构中对minor字段及name字段进行赋值,这样该驱动会在/dev目录下创建名为ls1b_buttons的设备文件,其中主设备号为10,次设备号为minor的值,即为143。

在struct miscdevice数据结构中,还有一个fops的字段,该字段为指向struct file_operations数据结构的指针。其中包括open、read、ioctl等字段,当用户程序调用open、write、ioctl函数时,最终调用该驱动的相应函数。

在LS1B_74LV165_button_open()函数中使能芯片74LV165用到的3个gpio口,并将端口设置为输出。当用户调用read函数时,运行驱动程序的LS1B_74LV165_button_read()函数,该函数调用button_read(),读取按键编码。在button_read()函数中调用prepare_for_read()根据芯片74LV165的时序将按键信息写入芯片74LV165的移位寄存器,然后调用scanf_keyboard()函数根据芯片74LV165的时序读写移位寄存器中的按键编码。最后通过LS1B_74LV165_button_read()函数中的copy_to_user()函数将按键编码返回给用户空间。

10-3RTC驱动程序

10-3-1 说明

程序源代码说明:

驱动源代码所在目录

/driver/rtc

驱动程序名称

rtc-gs2fsb.c

该驱动的主设备号

RTC设备,设备号将自动生成

设备名

/dev/rtc0

测试程序可执行文件名称

date hwclock

RTC模块寄存器位于0xbfe64000——0xbfe67fff的16KB地址空间内,其基地址为0xbfe64000,所有寄存器位宽均为32位。详细的寄存器描述可参考loongson 1B的数据手册。

10-3-2驱动程序清单

#include

#include

#include

#include

#include

#defineRTC_TOYIM0x00

#defineRTC_TOYWLO0x04

#defineRTC_TOYWHI0x08

#defineRTC_TOYRLO0x0c

#defineRTC_TOYRHI0x10

#defineRTC_TOYMH00x14

#defineRTC_TOYMH10x18

#defineRTC_TOYMH20x1c

#defineRTC_CNTL0x20

#defineRTC_RTCIM0x40

#defineRTC_WRITE00x44

#defineRTC_READ00x48

#defineRTC_RTCMH00x4c

#defineRTC_RTCMH10x50

#defineRTC_RTCMH20x54

struct rtc_sb2f{

struct rtc_device*rtc;

void __iomem*regs;

unsigned longalarm_time;

unsigned longirq;

spinlock_tlock;

};

static int sb2f_rtc_read_register(struct rtc_sb2f *rtc, unsigned long reg)

{

int data;

data = (*(volatile unsigned int *)(rtc->regs + reg));

return data;

}

static int sb2f_rtc_write_register(struct rtc_sb2f *rtc, unsigned long reg, int data)

{

(*(volatile unsigned int *)(rtc->regs + reg)) = data;

}

static int sb2f_rtc_readtime(struct device *dev, struct rtc_time *tm)

{

struct rtc_sb2f*rtc = dev_get_drvdata(dev);

unsigned long now, now1;

now = sb2f_rtc_read_register(rtc, RTC_TOYRLO);

tm->tm_sec = ((now >> 4) & 0x3f);

tm->tm_min = ((now >> 10) & 0x3f);

tm->tm_hour = ((now >> 16) & 0x1f);

tm->tm_mday = ((now >> 21) & 0x1f);

tm->tm_mon = ((now >> 26) & 0x3f) -1;

now1 = sb2f_rtc_read_register(rtc, RTC_TOYRHI);

tm->tm_year = (now1 -1900) ;

return 0;

}

static int sb2f_rtc_settime(struct device *dev, struct rtc_time *tm)

{

struct rtc_sb2f *rtc = dev_get_drvdata(dev);

unsigned long now;

int ret;

now = ((tm->tm_sec

(tm->tm_mday

spin_lock_irq(&rtc->lock);

sb2f_rtc_write_register(rtc, RTC_TOYWLO, now);

//set year

sb2f_rtc_write_register(rtc, RTC_TOYWHI, (tm->tm_year+1900) );

spin_unlock_irq(&rtc->lock);

return 0;

}

static int sb2f_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)

{

struct rtc_sb2f *rtc = dev_get_drvdata(dev);

unsigned long time;

spin_lock_irq(&rtc->lock);

time = sb2f_rtc_read_register(rtc, RTC_TOYMH0);

spin_unlock_irq(&rtc->lock);

alrm->time.tm_sec = (time & 0x3f);

alrm->time.tm_min = ((time >> 6) & 0x3f);

alrm->time.tm_hour = ((time >> 12) & 0x1f);

alrm->time.tm_mday = ((time >> 17) & 0x1f);

alrm->time.tm_mon = ((time >> 22) & 0x1f);

alrm->time.tm_year = ((time >> 26) & 0x3f);

return 0;

}

static int sb2f_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)

{

struct rtc_sb2f *rtc = dev_get_drvdata(dev);

int time;

time =(( alrm->time.tm_sec & 0x3f) | ((alrm->time.tm_min & 0x3f) <

| ((alrm->time.tm_hour & 0x1f)

& 0x1f)

((alrm->time.tm_year & 0x3f) <

spin_lock_irq(&rtc->lock);

sb2f_rtc_write_register(rtc, RTC_TOYMH0, time);

spin_unlock_irq(&rtc->lock);

return 0;

}

static int sb2f_rtc_ioctl(struct device *dev, unsigned int cmd,

unsigned long arg)

{

switch(cmd) {

case RTC_PIE_ON:

break;

case RTC_PIE_OFF:

break;

case RTC_UIE_ON:

break;

case RTC_UIE_OFF:

break;

case RTC_AIE_ON:

break;

case RTC_AIE_OFF:

break;

default:

return -ENOIOCTLCMD;

}

return 0;

}

static irqreturn_t sb2f_rtc_interrupt(int irq, void *dev_id)

{

struct rtc_sb2f *rtc = (struct rtc_sb2f *)dev_id;/*接收申请中断时传递过来的rtc_dev参数*/

unsigned long events = 0;

spin_lock(&rtc->lock);

events = RTC_AF | RTC_IRQF;

/*节拍时间中断到来的时候,去设定RTC中节拍时间的相关信息,具体设定的方法,RTC核心部分已经在rtc_update_irq接口函数中实现,函数定义实现在interface.c中*/

rtc_update_irq(rtc->rtc, 1, events);

spin_unlock(&rtc->lock);

}

static struct rtc_class_ops sb2f_rtc_ops = {

.ioctl= sb2f_rtc_ioctl,

.read_time= sb2f_rtc_readtime,

.set_time= sb2f_rtc_settime,

.read_alarm= sb2f_rtc_readalarm,

.set_alarm= sb2f_rtc_setalarm,

};

static int __init sb2f_rtc_probe(struct platform_device *pdev)

{

struct resource *regs;/*定义一个资源,用来保存获取的RTC的资源*/

struct rtc_sb2f *rtc;

int    irq = -1;

int    ret;

rtc = kzalloc(sizeof(struct rtc_sb2f), GFP_KERNEL);

if (!rtc) {

dev_dbg(&pdev->dev, "out of memory\n");

return -ENOMEM;

}

/*获取RTC平台设备所使用的IO端口资源,注意这个IORESOURCE_MEM标志和RTC平台设备定义中的一致*/

regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);

if (!regs) {

dev_dbg(&pdev->dev, "no nmio resource defined\n");

ret = -ENXIO;

goto out;

}

printk("the regs->start is 0x%x", regs->start);

//在系统定义的RTC平台设备中获取TICK节拍时间中断号

irq = platform_get_irq(pdev, 0);

printk("the irq is %d\n", irq);

rtc->irq = irq;

//把I/O资源IORESOURCE_MEM起始地址到结束地址范围的 资源映射到虚拟地址ioremap定义在io.h中。

//注意:IO空间要映射后才能使用,以后对虚拟地址的操作就是对IO空间的操作

rtc->regs = ioremap(regs->start, regs->end - regs->start + 1);

if (!rtc->regs) {

ret = -ENOMEM;

dev_dbg(&pdev->dev, "could not map i/o memory\n");

goto out;

}

//初始化自旋锁

spin_lock_init(&rtc->lock);

//next set control register

//sb2f_rtc_write_register(rtc, RTC_CNTL, 0x800);

(*(volatile int *)(0xbfe64040)) = 0x2d00;//TOY和RTC控制寄存器

//0010 1101 0000 0000

//申请中断(这个可以放到open()函数里)

//res->start 中断号(在具体的平台设备platform_device定义时赋值)

//s3c2410wdt_irq 中断处理函数IRQF_DISABLED中断处理属性 快速慢速共享

//pdev->name 这个传递给request_irq的字串用在/proc/interrupts来显示中断的拥有者

//pdev 用作共享中断线的指针 被驱动用来指向它自己的私有数据区(来标识哪个设备在中断).

ret = request_irq(irq, sb2f_rtc_interrupt, IRQF_SHARED, "rtc", rtc);

if (ret) {

dev_dbg(&pdev->dev, "could not request irq %d", irq);

goto out_iounmap;

}

//注册RTC设备

/* register RTC and exit */

/*将RTC注册为RTC设备类,RTC设备类在RTC驱动核心部分中由系统定义好的,

注意rtcops这个参数是一个结构体,该结构体的作用和里面的接口函数实现在第③步中。

rtc_device_register函数在rtc.h中定义,在drivers/rtc/class.c中实现*/

rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &sb2f_rtc_ops, THIS_MODULE);

/*里的IS_ERR(),它就是判断kthread_run()返回的指针是否有错,如果指针并不是指向最后一个page,那么没有问题,申请成功了,如果指针指向了最后一个page,那么说明实际上这不是一个有效的指针,这个指针里保存的实际上是一种错误代码.而通常很常用的方法就是先用IS_ERR()来判断是否是错误,然后如果是,那么就调用PTR_ERR()来返回这个错误代码.*/

if (IS_ERR(rtc->rtc)) {

dev_dbg(&pdev->dev, "could not register rtc device\n");

//PTR_ERR()只是返回错误代码,也就是提供一个信息给调用者,如果你只需要知道是否出错,而不在乎因为什么而出错

ret = PTR_ERR(rtc->rtc);

goto out_free_irq;

}

/*将RTC设备类的数据传递给系统平台设备。

platform_set_drvdata是定义在platform_device.h的宏,如下:

#define platform_set_drvdata(_dev,data)    dev_set_drvdata(&(_dev)->dev, (data))

而dev_set_drvdata又被定义在include/linux/device.h中,如下:

static inline void dev_set_drvdata (struct device *dev, void *data){

dev->driver_data = data;

}*/

platform_set_drvdata(pdev, rtc);

/*device_init_wakeup该函数定义在pm_wakeup.h中,定义如下:

static inline void device_init_wakeup(struct device *dev, int val){

dev->power.can_wakeup = dev->power.should_wakeup = !!val;}

显然这个函数是让驱动支持电源管理的,这里只要知道,can_wakeup为1时表明这个设备可以被唤醒,设备驱动为了支持Linux中的电源管理,有责任调用device_init_wakeup()来初始化can_wakeup,而should_wakeup则是在设备的电源状态发生变化的时候被device_may_wakeup()用来测试,测试它该不该变化,因此can_wakeup表明的是一种能力,而should_wakeup表明的是有了这种能力以后去不去做某件事。好了,我们没有必要深入研究电源管理的内容了,要不就扯远了,电源管理以后再讲*/

device_init_wakeup(&pdev->dev, 1);

//头文件include/linux/device.h中所提供的宏(包括dev_printk()、dev_dbg()、dev_warn()、dev_info()和dev_err())来决定何种类型的设备访问消息需要被记录。printk()

dev_info(&pdev->dev, "SB2F RTC  at %08lx irq %ld \n", (unsigned long)rtc->regs, rtc->irq);

return 0;

out_free_irq:

free_irq(irq, rtc);

out_iounmap:

iounmap(rtc->regs);

out:

kfree(rtc);

return ret;

}

/*注意:这是使用了一个__devexit。

我们还是先来讲讲这个:

在Linux内核中,使用了大量不同的宏来标记具有不同作用的函数和数据结构,

这些宏在include/linux/init.h头文件中定义,编译器通过这些宏可以把代码优化放到合适的内存位置,

以减少内存占用和提高内核效率。__devinit、__devexit就是这些宏之一,在probe()和remove()函数中

应该使用__devinit和__devexit宏。又当remove()函数使用了__devexit宏时,则在驱动结构体中一定要

使用__devexit_p宏来引用remove(),所以在第①步中就用__devexit_p来引用rtc_remove*/

static int __exit sb2f_rtc_remove(struct platform_device *pdev)

{

/*从系统平台设备中获取RTC设备类的数据*/

struct rtc_sb2f *rtc = platform_get_drvdata(pdev);

device_init_wakeup(&pdev->dev, 0);

free_irq(rtc->irq, rtc);

iounmap(rtc->regs);/*释放RTC虚拟地址映射空间*/

rtc_device_unregister(rtc->rtc);/*注销RTC设备类*/

kfree(rtc);/*销毁保存RTC平台设备的资源内存空间*/

platform_set_drvdata(pdev, NULL);/*清空平台设备中RTC驱动数据*/

return 0;

}

MODULE_ALIAS("platform:sb2f-rtc");

static struct platform_driver sb2f_rtc_driver = {

.remove= __exit_p(sb2f_rtc_remove),

.driver= {

.name= "sb2f-rtc",

.owner= THIS_MODULE,

},

};

static int __init sb2f_rtc_init(void)

{

/*将RTC注册成平台设备驱动*/

return platform_driver_probe(&sb2f_rtc_driver, sb2f_rtc_probe);

}

module_init(sb2f_rtc_init);

static void __exit sb2f_rtc_exit(void)

{

/*注销RTC平台设备驱动*/

platform_driver_unregister(&sb2f_rtc_driver);

}

module_exit(sb2f_rtc_exit);

MODULE_AUTHOR("");

MODULE_DESCRIPTION("Real Time clock for loongson2fsb");

MODULE_LICENSE("GPL");

linux下怎样运行oyrhon,第十章 LINUX驱动程序实验相关推荐

  1. linux下怎样运行oyrhon,Linux 下从头再走 GTK+-3.0 (一)

    原本由于项目需求在 Linux 下学习过一段时间的 GTK+2.0 图形开发,时隔一段时间,想真正深入学习一下 GTK . 这次直接从头学习 GTK+-3.0 ,并写下博文便于日后查看,也方便新手入门 ...

  2. linux下怎么运行2048,如何在 Linux 中安装 2048 游戏

    流行的移动益智游戏 2048 也可以在 Ubuntu 和 Linux 发行版上玩.啊!你甚至可以在 Linux 终端上玩 2048.如果你的生产率因为这个让人上瘾的游戏下降,请不要怪我. 早在 201 ...

  3. linux下怎样运行oyrhon,Fedora CoreOS基础操作,包括安装并运行Fedora CoreOS

    如果不知从何处入手Fedora CoreOS,那就看看本文,内容有:Fedora CoreOS的理念.入门.创建配置.安装并运行Fedora CoreOS.zincati,rpm-ostree和自动更 ...

  4. linux下软件编译终止,[2018年最新整理]linux下编译运行程序命令大全.ppt

    [2018年最新整理]linux下编译运行程序命令大全 1. 项目课题引入 2. Vi编辑器的使用方法 3. Linux中C语言程序的编辑 4. Linux中C语言程序的运行 5. 现场演示案例 课题 ...

  5. 解决aapt命令在Linux下无法运行的问题

    解决aapt命令在Linux下无法运行的问题 参考文章: (1)解决aapt命令在Linux下无法运行的问题 (2)https://www.cnblogs.com/zhjsll/p/5961291.h ...

  6. Linux 下后台运行程序,查看和关闭后台运行程序(转载)

    1.运行.sh文件 直接用./sh 文件就可以运行,但是如果想后台运行,即使关闭当前的终端也可以运行的话,需要nohup命令和&命令. (1)&命令 功能:加在一个命令的最后,可以把这 ...

  7. Linux下Fluent运行脚本及PBS脚本、Fluent TUI指令和Tecplot的一些操作

    Linux下Fluent运行脚本及PBS脚本.Fluent TUI指令和Tecplot的一些操作 目录 Linux下Fluent运行脚本及PBS脚本.Fluent TUI指令和Tecplot的一些操作 ...

  8. samba服务器在linux下如何运行共享

    samba服务器在linux下如何运行共享 1. 什么是samba Samba服务类似于windows上的共享功能,可以实现在Linux上共享文件,windows上访问,当然在Linux上也可以访问到 ...

  9. linux下查看进程的线程数,linux查看进程的线程数

    top -H -p $PID  #查看对应进程的那个线程占用CPU过高 1.top -H 手册中说:-H : Threads toggle 加上这个选项启动top,top一行显示一个线程.否则,它一行 ...

最新文章

  1. 关于Quartz的Job 不能被注入以及SpringAop对Job失效
  2. 整合spring cloud云架构 - SSO单点登录之OAuth2.0登录认证(1)
  3. 【CSS练习】IT修真院--练习4-移动端界面
  4. amuse ui(web插件,js插件,css样式)?
  5. android studio资产目录,在Android Studio中设置单元测试的自定义资产目录
  6. php接收arduino向服务器发来的请求
  7. 织梦响应式个人博客资讯网站模板(自适应手机移动端)
  8. rx580网络适配器下载_通过Rx和数据绑定简化RecyclerView适配器
  9. 快速了解前端开发HTML的正确姿势
  10. [Web Chart系列之六] canvas Chart 导出图文件
  11. python画饼图存在的问题_python_使用matplotlib画饼状图(pie)
  12. 游戏开发经验分享:我所理解的打击感
  13. 关于Adobe软件安装失败的各类错误代码BUG汇总!!
  14. 把自定义encoder加入ffmpeg源码
  15. cookie 和session
  16. quickpcb添加pcb库_QuickPcb元件库下载
  17. 学习笔记:CentOS7学习之十六:LVM管理和ssm存储管理器使用
  18. 人工智能学习路线图(超详细、超全面)
  19. Linux之setenv()/getenv()设置/获取环境变量
  20. 如何用几何画板把圆奇数等分

热门文章

  1. linux下socket编程实现一个服务器连接多个客户端
  2. BERT详解:概念、原理与应用
  3. iOS第三方集成之jpush极光推送
  4. javascript与html5实战
  5. 以《哈利波特》人物为例,学用Python处理csv模块
  6. 删除Flash控件的 Flash9e.ocx和FlashUtil9e.exe
  7. Docker版 Linux百度网盘备份工具
  8. JVM存储区划分及是否线程隔离
  9. 【前端技巧】实现点击复制文本内容方法
  10. 计算机无法访问同网络ip,\\+IP无法访问局域网用户