⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gpio.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		if (priv->write_msb) {			for (i = 7; i >= 0;i--) {				local_irq_save(flags);				shadow = *port;				*port = shadow &= ~clk_mask;				if (data & 1<<i)					*port = shadow |= data_mask;				else					*port = shadow &= ~data_mask;			/* For FPGA: min 5.0ns (DCC) before CCLK high */				*port = shadow |= clk_mask;				local_irq_restore(flags);			}		} else {			for (i = 0; i <= 7;i++) {				local_irq_save(flags);				shadow = *port;				*port = shadow &= ~clk_mask;				if (data & 1<<i)					*port = shadow |= data_mask;				else					*port = shadow &= ~data_mask;			/* For FPGA: min 5.0ns (DCC) before CCLK high */				*port = shadow |= clk_mask;				local_irq_restore(flags);			}		}	}	return retval;}static intgpio_open(struct inode *inode, struct file *filp){	struct gpio_private *priv;	int p = iminor(inode);	if (p > GPIO_MINOR_LAST)		return -EINVAL;	priv = kmalloc(sizeof(struct gpio_private),					      GFP_KERNEL);	if (!priv)		return -ENOMEM;	priv->minor = p;	/* initialize the io/alarm struct and link it into our alarmlist */	priv->next = alarmlist;	alarmlist = priv;	priv->clk_mask = 0;	priv->data_mask = 0;	priv->highalarm = 0;	priv->lowalarm = 0;	init_waitqueue_head(&priv->alarm_wq);	filp->private_data = (void *)priv;	return 0;}static intgpio_release(struct inode *inode, struct file *filp){	struct gpio_private *p = alarmlist;	struct gpio_private *todel = (struct gpio_private *)filp->private_data;	/* local copies while updating them: */	unsigned long a_high, a_low;	unsigned long some_alarms;	/* unlink from alarmlist and free the private structure */	if (p == todel) {		alarmlist = todel->next;	} else {		while (p->next != todel)			p = p->next;		p->next = todel->next;	}	kfree(todel);	/* Check if there are still any alarms set */	p = alarmlist;        some_alarms = 0;	a_high = 0;	a_low = 0;	while (p) {		if (p->minor == GPIO_MINOR_A) {			a_high |= p->highalarm;			a_low |= p->lowalarm;		}		if (p->highalarm | p->lowalarm) {			some_alarms = 1;		}		p = p->next;	}	spin_lock(&alarm_lock);	gpio_some_alarms = some_alarms;	gpio_pa_high_alarms = a_high;	gpio_pa_low_alarms = a_low;	spin_unlock(&alarm_lock);	return 0;}/* Main device API. ioctl's to read/set/clear bits, as well as to * set alarms to wait for using a subsequent select(). */unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg){	/* Set direction 0=unchanged 1=input,	 * return mask with 1=input	 */	unsigned long flags;	unsigned long dir_shadow;	local_irq_save(flags);	dir_shadow = *dir_oe[priv->minor];	dir_shadow &= ~(arg & changeable_dir[priv->minor]);	*dir_oe[priv->minor] = dir_shadow;	local_irq_restore(flags);	if (priv->minor == GPIO_MINOR_A)		dir_shadow ^= 0xFF;    /* Only 8 bits */	else		dir_shadow ^= 0x3FFFF; /* Only 18 bits */	return dir_shadow;} /* setget_input */unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg){	unsigned long flags;	unsigned long dir_shadow;	local_irq_save(flags);	dir_shadow = *dir_oe[priv->minor];	dir_shadow |=  (arg & changeable_dir[priv->minor]);	*dir_oe[priv->minor] = dir_shadow;	local_irq_restore(flags);	return dir_shadow;} /* setget_output */static intgpio_leds_ioctl(unsigned int cmd, unsigned long arg);static intgpio_ioctl(struct inode *inode, struct file *file,	   unsigned int cmd, unsigned long arg){	unsigned long flags;	unsigned long val;	unsigned long shadow;	struct gpio_private *priv = (struct gpio_private *)file->private_data;	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {		return -EINVAL;	}	switch (_IOC_NR(cmd)) {	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */		// read the port		return *data_in[priv->minor];		break;	case IO_SETBITS:		local_irq_save(flags);                if (arg & 0x04)                  printk("GPIO SET 2\n");		// set changeable bits with a 1 in arg		shadow = *data_out[priv->minor];		shadow |=  (arg & changeable_bits[priv->minor]);		*data_out[priv->minor] = shadow;		local_irq_restore(flags);		break;	case IO_CLRBITS:		local_irq_save(flags);                if (arg & 0x04)                  printk("GPIO CLR 2\n");		// clear changeable bits with a 1 in arg		shadow = *data_out[priv->minor];		shadow &=  ~(arg & changeable_bits[priv->minor]);		*data_out[priv->minor] = shadow;		local_irq_restore(flags);		break;	case IO_HIGHALARM:		// set alarm when bits with 1 in arg go high		priv->highalarm |= arg;		spin_lock(&alarm_lock);		gpio_some_alarms = 1;		if (priv->minor == GPIO_MINOR_A) {			gpio_pa_high_alarms |= arg;		}		spin_unlock(&alarm_lock);		break;	case IO_LOWALARM:		// set alarm when bits with 1 in arg go low		priv->lowalarm |= arg;		spin_lock(&alarm_lock);		gpio_some_alarms = 1;		if (priv->minor == GPIO_MINOR_A) {			gpio_pa_low_alarms |= arg;		}		spin_unlock(&alarm_lock);		break;	case IO_CLRALARM:		// clear alarm for bits with 1 in arg		priv->highalarm &= ~arg;		priv->lowalarm  &= ~arg;		spin_lock(&alarm_lock);		if (priv->minor == GPIO_MINOR_A) {			if (gpio_pa_high_alarms & arg ||			    gpio_pa_low_alarms & arg) {				/* Must update the gpio_pa_*alarms masks */			}		}		spin_unlock(&alarm_lock);		break;	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */		/* Read direction 0=input 1=output */		return *dir_oe[priv->minor];	case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */		/* Set direction 0=unchanged 1=input,		 * return mask with 1=input		 */		return setget_input(priv, arg);		break;	case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */		/* Set direction 0=unchanged 1=output,		 * return mask with 1=output		 */		return setget_output(priv, arg);	case IO_CFG_WRITE_MODE:	{		unsigned long dir_shadow;		dir_shadow = *dir_oe[priv->minor];		priv->clk_mask = arg & 0xFF;		priv->data_mask = (arg >> 8) & 0xFF;		priv->write_msb = (arg >> 16) & 0x01;		/* Check if we're allowed to change the bits and		 * the direction is correct		 */		if (!((priv->clk_mask & changeable_bits[priv->minor]) &&		      (priv->data_mask & changeable_bits[priv->minor]) &&		      (priv->clk_mask & dir_shadow) &&		      (priv->data_mask & dir_shadow)))		{			priv->clk_mask = 0;			priv->data_mask = 0;			return -EPERM;		}		break;	}	case IO_READ_INBITS:		/* *arg is result of reading the input pins */		val = *data_in[priv->minor];		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))			return -EFAULT;		return 0;		break;	case IO_READ_OUTBITS:		 /* *arg is result of reading the output shadow */		val = *data_out[priv->minor];		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))			return -EFAULT;		break;	case IO_SETGET_INPUT:		/* bits set in *arg is set to input,		 * *arg updated with current input pins.		 */		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))			return -EFAULT;		val = setget_input(priv, val);		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))			return -EFAULT;		break;	case IO_SETGET_OUTPUT:		/* bits set in *arg is set to output,		 * *arg updated with current output pins.		 */		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))			return -EFAULT;		val = setget_output(priv, val);		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))			return -EFAULT;		break;	default:		if (priv->minor == GPIO_MINOR_LEDS)			return gpio_leds_ioctl(cmd, arg);		else			return -EINVAL;	} /* switch */	return 0;}static intgpio_leds_ioctl(unsigned int cmd, unsigned long arg){	unsigned char green;	unsigned char red;	switch (_IOC_NR(cmd)) {	case IO_LEDACTIVE_SET:		green = ((unsigned char) arg) & 1;		red   = (((unsigned char) arg) >> 1) & 1;		LED_ACTIVE_SET_G(green);		LED_ACTIVE_SET_R(red);		break;	default:		return -EINVAL;	} /* switch */	return 0;}const struct file_operations gpio_fops = {	.owner       = THIS_MODULE,	.poll        = gpio_poll,	.ioctl       = gpio_ioctl,	.write       = gpio_write,	.open        = gpio_open,	.release     = gpio_release,};/* main driver initialization routine, called from mem.c */static __init intgpio_init(void){	int res;	reg_intr_vect_rw_mask intr_mask;	/* do the formalities */	res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);	if (res < 0) {		printk(KERN_ERR "gpio: couldn't get a major number.\n");		return res;	}	/* Clear all leds */	LED_NETWORK_SET(0);	LED_ACTIVE_SET(0);	LED_DISK_READ(0);	LED_DISK_WRITE(0);	printk("ETRAX FS GPIO driver v2.5, (c) 2003-2005 Axis Communications AB\n");	/* We call etrax_gpio_wake_up_check() from timer interrupt and	 * from cpu_idle() in kernel/process.c	 * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms	 * in some tests.	 */	if (request_irq(TIMER_INTR_VECT, gpio_poll_timer_interrupt,			IRQF_SHARED | IRQF_DISABLED,"gpio poll", &alarmlist)) {		printk("err: timer0 irq for gpio\n");	}	if (request_irq(GEN_IO_INTR_VECT, gpio_pa_interrupt,			IRQF_SHARED | IRQF_DISABLED,"gpio PA", &alarmlist)) {		printk("err: PA irq for gpio\n");	}	/* enable the gio and timer irq in global config */	intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);	intr_mask.timer = 1;	intr_mask.gen_io = 1;	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);	return res;}/* this makes sure that gpio_init is called during kernel boot */module_init(gpio_init);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -