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

📄 gpio.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	filp->private_data = (void *)priv;	return 0;}static intgpio_release(struct inode *inode, struct file *filp){	struct gpio_private *p;	struct gpio_private *todel;	spin_lock(&gpio_lock);        p = alarmlist;        todel = (struct gpio_private *)filp->private_data;	/* 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;	while (p) {		if (p->highalarm | p->lowalarm) {			gpio_some_alarms = 1;			spin_unlock(&gpio_lock);			return 0;		}		p = p->next;	}	gpio_some_alarms = 0;	spin_unlock(&gpio_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;	if (USE_PORTS(priv)) {		local_irq_save(flags);		*priv->dir = *priv->dir_shadow &= 		~((unsigned char)arg & priv->changeable_dir);		local_irq_restore(flags);		return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */	} else if (priv->minor == GPIO_MINOR_G) {		/* We must fiddle with R_GEN_CONFIG to change dir */		local_irq_save(flags);		if (((arg & dir_g_in_bits) != arg) && 		    (arg & changeable_dir_g)) {			arg &= changeable_dir_g;			/* Clear bits in genconfig to set to input */			if (arg & (1<<0)) {				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir);				dir_g_in_bits |= (1<<0);				dir_g_out_bits &= ~(1<<0);			}			if ((arg & 0x0000FF00) == 0x0000FF00) {				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir);				dir_g_in_bits |= 0x0000FF00;				dir_g_out_bits &= ~0x0000FF00;			}			if ((arg & 0x00FF0000) == 0x00FF0000) {				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir);				dir_g_in_bits |= 0x00FF0000;				dir_g_out_bits &= ~0x00FF0000;			}			if (arg & (1<<24)) {				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir);				dir_g_in_bits |= (1<<24);				dir_g_out_bits &= ~(1<<24);			}			D(printk(KERN_INFO "gpio: SETINPUT on port G set "				 "genconfig to 0x%08lX "				 "in_bits: 0x%08lX "				 "out_bits: 0x%08lX\n",			         (unsigned long)genconfig_shadow,			         dir_g_in_bits, dir_g_out_bits));			*R_GEN_CONFIG = genconfig_shadow;			/* Must be a >120 ns delay before writing this again */						}		local_irq_restore(flags);		return dir_g_in_bits;	}	return 0;} /* setget_input */unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg){	unsigned long flags;	if (USE_PORTS(priv)) {		local_irq_save(flags);		*priv->dir = *priv->dir_shadow |= 		  ((unsigned char)arg & priv->changeable_dir);		local_irq_restore(flags);		return *priv->dir_shadow;	} else if (priv->minor == GPIO_MINOR_G) {		/* We must fiddle with R_GEN_CONFIG to change dir */					local_irq_save(flags);		if (((arg & dir_g_out_bits) != arg) &&		    (arg & changeable_dir_g)) {			/* Set bits in genconfig to set to output */			if (arg & (1<<0)) {				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir);				dir_g_out_bits |= (1<<0);				dir_g_in_bits &= ~(1<<0);			}			if ((arg & 0x0000FF00) == 0x0000FF00) {				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir);				dir_g_out_bits |= 0x0000FF00;				dir_g_in_bits &= ~0x0000FF00;			}			if ((arg & 0x00FF0000) == 0x00FF0000) {				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir);				dir_g_out_bits |= 0x00FF0000;				dir_g_in_bits &= ~0x00FF0000;			}			if (arg & (1<<24)) {				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir);				dir_g_out_bits |= (1<<24);				dir_g_in_bits &= ~(1<<24);			}			D(printk(KERN_INFO "gpio: SETOUTPUT on port G set "				 "genconfig to 0x%08lX "				 "in_bits: 0x%08lX "				 "out_bits: 0x%08lX\n",			         (unsigned long)genconfig_shadow,			         dir_g_in_bits, dir_g_out_bits));			*R_GEN_CONFIG = genconfig_shadow;			/* Must be a >120 ns delay before writing this again */		}		local_irq_restore(flags);		return dir_g_out_bits & 0x7FFFFFFF;	}	return 0;} /* 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;        int ret = 0;	struct gpio_private *priv = (struct gpio_private *)file->private_data;	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {		return -EINVAL;	}	spin_lock(&gpio_lock);	switch (_IOC_NR(cmd)) {	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */		// read the port		if (USE_PORTS(priv)) {			ret =  *priv->port;		} else if (priv->minor == GPIO_MINOR_G) {			ret =  (*R_PORT_G_DATA) & 0x7FFFFFFF;		}		break;	case IO_SETBITS:		local_irq_save(flags);		// set changeable bits with a 1 in arg		if (USE_PORTS(priv)) {			*priv->port = *priv->shadow |= 			  ((unsigned char)arg & priv->changeable_bits);		} else if (priv->minor == GPIO_MINOR_G) {			*R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits);		}		local_irq_restore(flags);		break;	case IO_CLRBITS:		local_irq_save(flags);		// clear changeable bits with a 1 in arg		if (USE_PORTS(priv)) {			*priv->port = *priv->shadow &= 			 ~((unsigned char)arg & priv->changeable_bits);		} else if (priv->minor == GPIO_MINOR_G) {			*R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits);		}		local_irq_restore(flags);		break;	case IO_HIGHALARM:		// set alarm when bits with 1 in arg go high		priv->highalarm |= arg;		gpio_some_alarms = 1;		break;	case IO_LOWALARM:		// set alarm when bits with 1 in arg go low		priv->lowalarm |= arg;		gpio_some_alarms = 1;		break;	case IO_CLRALARM:		// clear alarm for bits with 1 in arg		priv->highalarm &= ~arg;		priv->lowalarm  &= ~arg;		{			/* Must update gpio_some_alarms */			struct gpio_private *p = alarmlist;			int some_alarms;			some_alarms = 0;			while (p) {				if (p->highalarm | p->lowalarm) {					some_alarms = 1;					break;				}				p = p->next;			}			gpio_some_alarms = some_alarms;		}		break;	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */		/* Read direction 0=input 1=output */		if (USE_PORTS(priv)) {			ret = *priv->dir_shadow;		} else if (priv->minor == GPIO_MINOR_G) {			/* Note: Some bits are both in and out,			 * Those that are dual is set here as well.			 */			ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;		}		break;	case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */		/* Set direction 0=unchanged 1=input, 		 * return mask with 1=input 		 */		ret = setget_input(priv, arg) & 0x7FFFFFFF;		break;	case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */		/* Set direction 0=unchanged 1=output, 		 * return mask with 1=output 		 */		ret =  setget_output(priv, arg) & 0x7FFFFFFF;		break;	case IO_SHUTDOWN:		SOFT_SHUTDOWN();		break;	case IO_GET_PWR_BT:#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)		ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));#else		ret = 0;#endif		break;	case IO_CFG_WRITE_MODE:		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 & priv->changeable_bits) &&		      (priv->data_mask & priv->changeable_bits) &&		      (priv->clk_mask & *priv->dir_shadow) &&		      (priv->data_mask & *priv->dir_shadow)))		{			priv->clk_mask = 0;			priv->data_mask = 0;			ret = -EPERM;		}		break;	case IO_READ_INBITS: 		/* *arg is result of reading the input pins */		if (USE_PORTS(priv)) {			val = *priv->port;		} else if (priv->minor == GPIO_MINOR_G) {			val = *R_PORT_G_DATA;		}		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))			ret = -EFAULT;		break;	case IO_READ_OUTBITS:		 /* *arg is result of reading the output shadow */		if (USE_PORTS(priv)) {			val = *priv->shadow;		} else if (priv->minor == GPIO_MINOR_G) {			val = port_g_data_shadow;		}		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))			ret = -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)))		{			ret = -EFAULT;			break;		}		val = setget_input(priv, val);		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))			ret = -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)))		{			ret = -EFAULT;			break;		}		val = setget_output(priv, val);		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))			ret = -EFAULT;		break;	default:		if (priv->minor == GPIO_MINOR_LEDS)			ret = gpio_leds_ioctl(cmd, arg);		else			ret = -EINVAL;	} /* switch */	spin_unlock(&gpio_lock);	return ret;}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;	case IO_LED_SETBIT:		LED_BIT_SET(arg);		break;	case IO_LED_CLRBIT:		LED_BIT_CLR(arg);		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,};void ioif_watcher(const unsigned int gpio_in_available,		  const unsigned int gpio_out_available,		  const unsigned char pa_available,		  const unsigned char pb_available){	unsigned long int flags;	D(printk("gpio.c: ioif_watcher called\n"));	D(printk("gpio.c: G in: 0x%08x G out: 0x%08x PA: 0x%02x PB: 0x%02x\n",		 gpio_in_available, gpio_out_available, pa_available, pb_available));	spin_lock_irqsave(&gpio_lock, flags);	dir_g_in_bits = gpio_in_available;	dir_g_out_bits = gpio_out_available;	/* Initialise the dir_g_shadow etc. depending on genconfig */	/* 0=input 1=output */	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out)) 		dir_g_shadow |= (1 << 0);	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g8_15dir, out))		dir_g_shadow |= 0x0000FF00;	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g16_23dir, out))		dir_g_shadow |= 0x00FF0000;	if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out))		dir_g_shadow |= (1 << 24);	changeable_dir_g = changeable_dir_g_mask;	changeable_dir_g &= dir_g_out_bits;	changeable_dir_g &= dir_g_in_bits;	/* Correct the bits that can change direction */ 	dir_g_out_bits &= ~changeable_dir_g;	dir_g_out_bits |= dir_g_shadow;	dir_g_in_bits &= ~changeable_dir_g;	dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g);	spin_unlock_irqrestore(&gpio_lock, flags);	printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n",	       dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA);	printk(KERN_INFO "GPIO port G: dir: %08lX changeable: %08lX\n",	       dir_g_shadow, changeable_dir_g);}/* main driver initialization routine, called from mem.c */static __init intgpio_init(void){	int res;#if defined (CONFIG_ETRAX_CSP0_LEDS)	int i;#endif        printk("gpio init\n");	/* 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 */#if defined (CONFIG_ETRAX_CSP0_LEDS) ||  defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)	LED_NETWORK_SET(0);	LED_ACTIVE_SET(0);	LED_DISK_READ(0);	LED_DISK_WRITE(0);#if defined (CONFIG_ETRAX_CSP0_LEDS)	for (i = 0; i < 32; i++) {		LED_BIT_SET(i);	}#endif#endif	/* The I/O interface allocation watcher will be called when	 * registering it. */	if (cris_io_interface_register_watcher(ioif_watcher)){		printk(KERN_WARNING "gpio_init: Failed to install IO if allocator watcher\n");	}	printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002, 2003, 2004 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(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,			IRQF_SHARED | IRQF_DISABLED,"gpio poll", NULL)) {		printk(KERN_CRIT "err: timer0 irq for gpio\n");	}	if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,			IRQF_SHARED | IRQF_DISABLED,"gpio PA", NULL)) {		printk(KERN_CRIT "err: PA irq for gpio\n");	}		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 + -