参考文档
内核 Documentation/devicetree/bindings/Pinctrl/Pinctrl-bindings.txt
内核 Documentation/gpio/Pinctrl-bindings.txt
内核 Documentation/devicetree/bindings/gpio/gpio.txt
如何理解Pinctrl子系统?
Pinctrl子系统,顾名思义,就是管理pin引脚的一个系统,比如要点亮LED,即要控制LED对应引脚的高低电平,就要先通过Pintrl子系统将LED对应的引脚复用为GPIO功能 , 如此便不需要操作繁琐寄存器 , Pinctrl子系统依赖于设备树来使用 , 无论是哪种芯片,都有类似下图的结构:
要想让pinA、B用于GPIO,需要设置IOMUX让它们连接到GPIO模块;
要想让pinA、B用于I2C,需要设置IOMUX让它们连接到I2C模块。
使用Pinctrl子系统
这会涉及2个对象:pin controller、client device。
前者提供服务:可以用它来复用引脚、配置引脚。
后者使用服务:声明自己要使用哪些引脚的哪些功能,怎么配置它们。
pin controller:
在芯片手册里你找不到pin controller,它是一个软件上的概念,你可以认为它对应IOMUX──用来复用引脚,还可以配置引脚(比如上下拉电阻等)。
b. client device
“客户设备”,谁的客户?Pinctrl系统的客户,那就是使用Pinctrl系统的设备,使用引脚的设备。它在设备树里会被定义为一个节点,在节点里声明要用哪些引脚。
举例分析 pinctrl子系统
pinctrl用于引脚得复用, 在设备树中找到 iomuxc节点
以imx6ull为例:
imx6ull.dtsi中找到:
iomuxc: iomuxc@020e0000 {
compatible = "fsl,imx6ul-iomuxc";
reg = <0x020e0000 0x4000>;
};
imx6ull.dts中对其进行补充:
311 &iomuxc {
312 pinctrl-names = "default";
313 pinctrl-0 = <&pinctrl_hog_1>;
314 imx6ul-evk {
315 pinctrl_hog_1: hoggrp-1 {
316 fsl,pins = <
317 MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
318 MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059
319 MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059
320 MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x13058
321 >;
322 };
......
添加了一些宏,
190 #define MX6UL_PAD_UART1_RTS_B__UART1_DCE_RTS 0x0090 0x031C 0x0620 0x0 0x3
191 #define MX6UL_PAD_UART1_RTS_B__UART1_DTE_CTS 0x0090 0x031C 0x0000 0x0 0x0
192 #define MX6UL_PAD_UART1_RTS_B__ENET1_TX_ER 0x0090 0x031C 0x0000 0x1 0x0
193 #define MX6UL_PAD_UART1_RTS_B__USDHC1_CD_B 0x0090 0x031C 0x0668 0x2 0x1
194 #define MX6UL_PAD_UART1_RTS_B__CSI_DATA05 0x0090 0x031C 0x04CC 0x3 0x1
195 #define MX6UL_PAD_UART1_RTS_B__ENET2_1588_EVENT1_OUT 0x0090 0x031C 0x0000 0x4 0x0
196 #define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0
197 #define MX6UL_PAD_UART1_RTS_B__USDHC2_CD_B 0x0090 0x031C 0x0674 0x8 0x2
仔细观察应该就能发现,这 8个宏定义分别对应 UART1_RTS_B这个 PIN的 8个复用 IO
这 5个值的含义如下所示:
<mux_reg conf_reg input_reg mux_mode input_val> 分别设置了这些寄存器的值
mux_reg:复用寄存器地址
conf_reg:电气属性配置寄存器地址
input_reg:输入寄存器地址
mux_mode:引脚复用为什么模式, 也就是写入mux_reg的值
input_val:输入寄存器配置值
pinctrl子系统驱动程序便是调用这里的信息来复用引脚
0x0090:mux_reg寄存器偏移地址,设备树中的 iomuxc节点就是 IOMUXC外设对应的节
点 ,根据其 reg 属性可知 IOMUXC 外设寄存器起始地址为 0x020e0000 。因此可知,0x020e0000+mux_reg就是 PIN的复用寄存器地址。
0x031C:conf_reg寄存器偏移地址,和 mux_reg 一样,0x020e0000+0x031c=0x020e031c,
这个就是寄存器 IOMUXC_SW_PAD_CTL_P AD_UART1_RTS_B的地址。
0x0000:input_reg寄存器偏移地址,有些外设有 input_reg寄存器,有 input_reg寄存器的
外设需要配置 input_reg寄存器。没有的话就不需要设置,UART1_RTS_B这个 PIN在做
GPIO1_IO19的时候是没有 input_reg寄存器,因此这里 intput_reg是无效的。
0x5 : mux_reg 寄 存 器 值 , 在 这 里 就 相 当 于 设 置
IOMUXC_SW_MUX_CTL_PAD_UART1_RTS_B寄存器为 0x5,也即是设置 UART1_RTS_B这
个 PIN复用为 GPIO1_IO19。
0x0:input_reg寄存器值,在这里无效
0x17059就是 conf_reg寄存器值,此值由用户自行设置,通
过此值来设置一个 IO 的上 /下拉 、驱动能力和速度等 。在这里就相当于设置寄存器
IOMUXC_SW_P AD_CTL_PAD_UART1_RTS_B的值为 0x17059。
设备树中添加 pinctrl节点模板
找到对应的厂商的样板节点
如 6ull样板节点 在iomuxc节点
中的“imx6ul-evk”子节点
1、创建对应的节点
1 pinctrl_test: testgrp {
2
3 >;
2、添加“fsl,pins”属性
设备树是通过属性来保存信息的,因此我们需要添加一个属性,属性名字一定要为“fsl,pins”,
因为对于 I.MX系列 SOC而言,pinctrl驱动程序是通过读取“fsl,pins”属性值来获取 PIN的配
置信息,完成以后如下所示:
1 pinctrl_test: testgrp {
2 fsl,pins = <
3 /* 设备所使用的 PIN配置信息 */
4 >;
5 };
3、在“fsl,pins”属性中添加 PIN配置信息
最后在“fsl,pins”属性中添加具体的 PIN配置信息,完成以后如下所示:
1 pinctrl_test: testgrp {
2 fsl,pins = <
3 MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 config /*config是具体设置值*/
4 >;
5 };
GPIO子系统
当引脚被复用为gpio功能时, 就可以使用gpio子系统对此引脚进行操作
带有 属性 gpio-controller; 的节点就是gpioctrl 节点
#gpio-cells = <2> 表示这个控制器下每一个引脚要用2个32位的数(cell)来描述。
如何使用GPIO子系统
定义GPIO Controller是芯片厂家的事,我们怎么引用某个引脚呢?在自己的设备节点中使用属性"[-]gpios"
驱动代码中调用GPIO子系统
驱动程序中要包含头文件,
#include <linux/gpio/consumer.h>
下表列出常用的函数:
获得GPIO
gpiod_get
gpiod_get_index
gpiod_get_array
devm_gpiod_get
devm_gpiod_get_index
devm_gpiod_get_array
设置方向
gpiod_direction_input
gpiod_direction_output
读值、写值
gpiod_get_value
gpiod_set_value
释放GPIO
gpio_free
gpiod_put
gpiod_put_array
devm_gpiod_put
devm_gpiod_put_array
有前缀“devm_”的含义是“设备资源管理”(Managed Device Resource),这是一种自动释放资源的机制。它的思想是“资源是属于设备的,设备不存在时资源就可以自动释放
编写驱动,使用pinctrl . gpioctrl点亮led
1,根据原理图, 找到led的引脚
在设备树中要用到
LED0用到的引脚为GPIO1_IO03
2,修改设备树将设备节点加入设备树
添加设备子节点
(直接在根节点的子节点下添加即可)
指定pinctrl有几个必要的属性:
pinctrl-names
pinctrl-[No] ===> pinctrl-0, pinctrl-1…
gpioled{
compatible = "alientek,gpioled";//指定匹配的驱动
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpioled>;
status = "okay";
};
3,在设备树中指定好pinctrl
在&iomuxc节点添加子节点 (iomuxc顾名思义 io复用, 设备树中的体现就是用于pinctrl的定义)
引脚宏定义在文件 imx6ul-pinfunc.h中
显然我们需要的是 MX6UL_PAD_GPIO1_IO03_GPIO1_IO03 这个宏
pinctrl_gpioled:ledgrp{
fsl,pins = <
MX6UL_PAD_GPIO1_IO03_GPIO1_IO03 0x10b0
>;
};
0x10b0是电器属性, 需通过芯片手册查阅寄存器功能得出, (imx芯片有官方引脚配置工具可使用)
4,节点指定gpioctrl
必要属性有
[name-]gpios ===> led-gpios, gpios
gpioled{
compatible = "alientek,gpioled";//指定匹配的驱动
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpioled>;
led-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
status = "okay";
};
5,编译设备树生成dtb文件并使用
在内核目录下
make dtbs
查看设备节点是否生成
6,编写驱动代码
准备好makefile
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
# 请参考各开发板的高级用户使用手册
KERN_DIR = /home/yu/bsp_sdk_imax6ull/Linux-4.9.88
all:
make -C $(KERN_DIR) M=`pwd` modules
#
$(CROSS_COMPILE)gcc -o ledtest ledtest.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
rm -f ledtest
install:
#根据环境修改
cp *.ko ~/embedded_code/ledtest/
cp ledtest ~/embedded_code/ledtest/
# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.o
obj-m += gpioLed.o
编写好好字符设备驱动框架
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#define GPIOLED_CNT 1
#define GPIOLED_NAME "gpioled"
/*gpioled设备结构体*/
struct gpioled_dev{
dev_t devid; //设备号
int major; //主设备号
int minor; //次设备号
struct cdev cdev;
struct class *class;
struct device *device;
};
static struct gpioled_dev gpioled; /*"LED"*/
static int led_open(struct inode *, struct file *)
{
return 0;
}
static ssize_t led_write(struct file *, const char __user *, size_t, loff_t *)
{
return 0
}
static int led_close(struct inode *, struct file *)
{
return 0;
}
//定义自己的file_operations结构体
static struct file_operations led_fops ={
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.release = led_close,
};
/*驱动入口函数*/
static int __init led_init(void)
{
/*1.注册字符设备驱动*/
gpioled.major = 0; //为0由内核自动分配
gpioled.minor = 0; //次设备号从0开始
int ret = 0; //错误返回值
int i;
if(gpioled.major){ //给定了设备号 静态分配
gpioled.devid = MKDEV(gpioled.major, gpioled.minor);
/*2.4内核后推出的批量注册字符设备*/
ret = register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);
if(IS_ERR(ret)){
printk(KERN_ERR, "line:%d %s:%s *** register_chrdev_region fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto chrdev_fail;
}
}else{ //没给定设备号 由内核动态分配
//动态分配
/*
动态分配设备号到gpioled.devid
从次设备号为0开始 GPIOLED_CNT个设备,
名称为 GPIOLED_NAME
*/
ret = alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);
if(IS_ERR(ret)){
printk(KERN_ERR, "line:%d %s:%s *** alloc_register_chrdev_region fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto chrdev_fail;
}
gpioled.major = MAJOR(gpioled.devid);
gpioled.minor = MINOR(gpioled.devid);
printk("gpioled major = %d, minor = %d\r\n",
gpioled.major, gpioled.minor);
}
/*2.初始化cdev 将file_operations结构体放入cdev-> ops 里*/
gpioled.cdev.owner = THIS_MODULE;
ret = cdev_init(&gpioled.cdev, &led_fops);
if(IS_ERR(ret)){
printk(KERN_ERR, "line:%d %s:%s *** cdev_init fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto cdev_init_fail;
}
/*
3.添加cdev 将cdev结构体添加到系统中,
并将dev(注册好的设备编号)放入cdev->dev里,
count(次设备编号个数)放入cdev->count里
*/
ret = cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);
if(IS_ERR(ret)){
printk(KERN_ERR, "line:%d %s:%s *** cdev_add fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto cdev_add_fail;
}
/*
4.创建类
*/
gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);
if(IS_ERR(gpioled.class)){
printk(KERN_ERR, "line:%d %s:%s *** class_create fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto class_create_fail;
}
/*
5.创建设备
*/
gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);
if(IS_ERR(gpioled.device)){
printk(KERN_ERR, "line:%d %s:%s *** device_create fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto device_create_fail;
}
return 0;
device_create_fail:
class_destroy(gpioled.device);
class_create_fail:
cdev_add_fail:
cdev_del(&gpioled.cdev);
cdev_init_fail:
unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);
chrdev_fail:
return -EINVAL;
}
/*驱动出口函数*/
static void __exit led_exit(void)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
device_destroy(gpioled.class, gpioled.devid);
class_destroy(gpioled.class);
cdev_del(&gpioled.cdev);
unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);
}
module_init(led_init);
module_exit(led_exit);
MOUDLE_LICENSE("GPL");
MODULE_AUTHOR("jizhiyu");
字符设备驱动框架 中添加 对引脚的操作
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#define GPIOLED_CNT 1
#define GPIOLED_NAME "gpioled"
#define LEDOFF 0
#define LEDON 1
/*gpioled设备结构体*/
struct gpioled_dev{
dev_t devid; //设备号
int major; //主设备号
int minor; //次设备号
struct cdev cdev;
struct class *class;
struct device *device;
struct device_node *nd;
int led_gpio; //gpio编号
};
static struct gpioled_dev gpioled; /*"LED"*/
static int led_open(struct inode *node, struct file *filp)
{
return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
int ret ;
unsigned char databuf[1];
struct gpioled_dev *dev = filp->private_data;
ret = copy_from_user(databuf, buf, 1);
if(ret < 0){
return -EINVAL;
}
if(databuf[0] == LEDON){
gpio_set_value(gpioled.led_gpio, 0);
}else if(databuf[0] == LEDOFF){
gpio_set_value(gpioled.led_gpio, 1);
}
return 0
}
static int led_close(struct inode *node, struct file *filp)
{
return 0;
}
//定义自己的file_operations结构体
static struct file_operations led_fops ={
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.release = led_close,
};
/*驱动入口函数*/
static int __init led_init(void)
{
/*1.注册字符设备驱动*/
gpioled.major = 0; //为0由内核自动分配
gpioled.minor = 0; //次设备号从0开始
int ret = 0; //错误返回值
int i;
if(gpioled.major){ //给定了设备号 静态分配
gpioled.devid = MKDEV(gpioled.major, gpioled.minor);
/*2.4内核后推出的批量注册字符设备*/
ret = register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);
if(IS_ERR(ret)){
printk(KERN_ERR, "line:%d %s:%s *** register_chrdev_region fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto chrdev_fail;
}
}else{ //没给定设备号 由内核动态分配
//动态分配
/*
动态分配设备号到gpioled.devid
从次设备号为0开始 GPIOLED_CNT个设备,
名称为 GPIOLED_NAME
*/
ret = alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);
if(IS_ERR(ret)){
printk(KERN_ERR, "line:%d %s:%s *** alloc_register_chrdev_region fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto chrdev_fail;
}
gpioled.major = MAJOR(gpioled.devid);
gpioled.minor = MINOR(gpioled.devid);
printk("gpioled major = %d, minor = %d\r\n",
gpioled.major, gpioled.minor);
}
/*2.初始化cdev 将file_operations结构体放入cdev-> ops 里*/
gpioled.cdev.owner = THIS_MODULE;
ret = cdev_init(&gpioled.cdev, &led_fops);
if(IS_ERR(ret)){
printk(KERN_ERR, "line:%d %s:%s *** cdev_init fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto cdev_init_fail;
}
/*
3.添加cdev 将cdev结构体添加到系统中,
并将dev(注册好的设备编号)放入cdev->dev里,
count(次设备编号个数)放入cdev->count里
*/
ret = cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);
if(IS_ERR(ret)){
printk(KERN_ERR, "line:%d %s:%s *** cdev_add fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto cdev_add_fail;
}
/*
4.创建类
*/
gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);
if(IS_ERR(gpioled.class)){
printk(KERN_ERR, "line:%d %s:%s *** class_create fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto class_create_fail;
}
/*
5.创建设备
*/
gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);
if(IS_ERR(gpioled.device)){
printk(KERN_ERR, "line:%d %s:%s *** device_create fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto device_create_fail;
}
/*
1.获取设备节点
*/
gpioled.nd = of_find_node_by_path("/gpioled");
if(gpioled.nd == NULL){
printk(KERN_ERR, "line:%d %s:%s *** of_find_node_by_path fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto find_node_fail;
}
/*
2.获取LED所对应的GPIO
*/
gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led", 0);
if(IS_ERR(gpioled.led_gpio)){
printk(KERN_ERR, "line:%d %s:%s *** of_get_named_gpio fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto find_node_fail;
}
printk("led gpio num =%d\r\n", gpioled.led_gpio);
/*
3.申请IO
也可以使用gpiod_get函数 返回一个gpio_desc用于操作gpio
*/
ret = gpio_request(gpioled.led_gpio, "led-gpio");
if(ret){
printk(KERN_ERR, "line:%d %s:%s *** gpio_request fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto find_node_fail;
}
gpiod_get(struct device * dev, const char * con_id, enum gpiod_flags flags);
/*
4.设置IO为输出
也可以使用 gpiod_direction_output(struct gpio_desc * desc, int value)
*/
ret = gpio_direction_output(gpioled.led_gpio, 1);
if(IS_ERR(ret)){
printk(KERN_ERR, "line:%d %s:%s *** gpio_direction_output fail\n",
__LINE__, __FILE__, __FUNCTION__));
goto gpio_direction_output_fail;
}
gpiod_direction_output(struct gpio_desc * desc, int value)
/*
5.输出低电平, 点亮LED
也可以使用gpiod_set_value(struct gpio_desc * desc, int value)
*/
gpio_set_value(gpioled.led_gpio, 0);
gpiod_set_value(struct gpio_desc * desc, int value)
return 0;
return 0;
gpio_direction_output_fail:
gpio_free(gpioled.led_gpio);
//gpiod_free(struct gpio_desc * desc)
find_node_fail:
device_del(gpioled.device);
device_create_fail:
class_destroy(gpioled.device);
class_create_fail:
cdev_add_fail:
cdev_del(&gpioled.cdev);
cdev_init_fail:
unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);
chrdev_fail:
return -EINVAL;
}
/*驱动出口函数*/
static void __exit led_exit(void)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
gpio_set_value(gpioled.led_gpio, 1);
gpio_free(gpioled.led_gpio);
//gpiod_free(struct gpio_desc * desc)
device_destroy(gpioled.class, gpioled.devid);
class_destroy(gpioled.class);
cdev_del(&gpioled.cdev);
unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);
}
module_init(led_init);
module_exit(led_exit);
MOUDLE_LICENSE("GPL");
MODULE_AUTHOR("jizhiyu");
7,编写驱动测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
* ./ledtest /dev/100ask_led0 on
* ./ledtest /dev/100ask_led0 off
*/
int main(int argc, char **argv)
{
int fd;
char status;
/* 1. 判断参数 */
if (argc != 3)
{
printf("Usage: %s <dev> <on | off>\n", argv[0]);
return -1;
}
/* 2. 打开文件 */
fd = open(argv[1], O_RDWR);
if (fd == -1)
{
printf("can not open file %s\n", argv[1]);
return -1;
}
/* 3. 写文件 */
if (0 == strcmp(argv[2], "on"))
{
status = 1;
write(fd, &status, 1);
}
else
{
status = 0;
write(fd, &status, 1);
}
close(fd);
return 0;
}