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

📄 cm4000_cs.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
		/* is a card inserted and powered? */		if ((dev->flags0 & 0x01) && (dev->flags0 & 0x02)) {			/* get IO lock */			if (wait_event_interruptible			    (dev->ioq,			     ((filp->f_flags & O_NONBLOCK)			      || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)				  == 0)))) {				if (filp->f_flags & O_NONBLOCK)					return -EAGAIN;				return -ERESTARTSYS;			}			/* Set Flags0 = 0x42 */			DEBUGP(4, dev, "Set Flags0=0x42 \n");			xoutb(0x42, REG_FLAGS0(iobase));			clear_bit(IS_ATR_PRESENT, &dev->flags);			clear_bit(IS_ATR_VALID, &dev->flags);			dev->mstate = M_CARDOFF;			clear_bit(LOCK_IO, &dev->flags);			if (wait_event_interruptible			    (dev->atrq,			     ((filp->f_flags & O_NONBLOCK)			      || (test_bit(IS_ATR_VALID, (void *)&dev->flags) !=				  0)))) {				if (filp->f_flags & O_NONBLOCK)					return -EAGAIN;				return -ERESTARTSYS;			}		}		/* release lock */		clear_bit(LOCK_IO, &dev->flags);		wake_up_interruptible(&dev->ioq);		return 0;	case CM_IOCSPTS:		{			struct ptsreq krnptsreq;			if (copy_from_user(&krnptsreq, argp,					   sizeof(struct ptsreq)))				return -EFAULT;			rc = 0;			DEBUGP(4, dev, "... in CM_IOCSPTS\n");			/* wait for ATR to get valid */			if (wait_event_interruptible			    (dev->atrq,			     ((filp->f_flags & O_NONBLOCK)			      || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags)				  != 0)))) {				if (filp->f_flags & O_NONBLOCK)					return -EAGAIN;				return -ERESTARTSYS;			}			/* get IO lock */			if (wait_event_interruptible			    (dev->ioq,			     ((filp->f_flags & O_NONBLOCK)			      || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)				  == 0)))) {				if (filp->f_flags & O_NONBLOCK)					return -EAGAIN;				return -ERESTARTSYS;			}			if ((rc = set_protocol(dev, &krnptsreq)) != 0) {				/* auto power_on again */				dev->mstate = M_FETCH_ATR;				clear_bit(IS_ATR_VALID, &dev->flags);			}			/* release lock */			clear_bit(LOCK_IO, &dev->flags);			wake_up_interruptible(&dev->ioq);		}		return rc;#ifdef PCMCIA_DEBUG	case CM_IOSDBGLVL:	/* set debug log level */		{			int old_pc_debug = 0;			old_pc_debug = pc_debug;			if (copy_from_user(&pc_debug, argp, sizeof(int)))				return -EFAULT;			if (old_pc_debug != pc_debug)				DEBUGP(0, dev, "Changed debug log level "				       "to %i\n", pc_debug);		}		return rc;#endif	default:		DEBUGP(4, dev, "... in default (unknown IOCTL code)\n");		return -EINVAL;	}}static int cmm_open(struct inode *inode, struct file *filp){	struct cm4000_dev *dev;	dev_link_t *link;	int rc, minor = iminor(inode);	if (minor >= CM4000_MAX_DEV)		return -ENODEV;	link = dev_table[minor];	if (link == NULL || !(DEV_OK(link)))		return -ENODEV;	if (link->open)		return -EBUSY;	dev = link->priv;	filp->private_data = dev;	DEBUGP(2, dev, "-> cmm_open(device=%d.%d process=%s,%d)\n",	      imajor(inode), minor, current->comm, current->pid);	/* init device variables, they may be "polluted" after close	 * or, the device may never have been closed (i.e. open failed)	 */	ZERO_DEV(dev);	/* opening will always block since the	 * monitor will be started by open, which	 * means we have to wait for ATR becoming	 * vaild = block until valid (or card	 * inserted)	 */	if (filp->f_flags & O_NONBLOCK)		return -EAGAIN;	dev->mdelay = T_50MSEC;	/* start monitoring the cardstatus */	start_monitor(dev);	link->open = 1;		/* only one open per device */	rc = 0;	DEBUGP(2, dev, "<- cmm_open\n");	return nonseekable_open(inode, filp);}static int cmm_close(struct inode *inode, struct file *filp){	struct cm4000_dev *dev;	dev_link_t *link;	int minor = iminor(inode);	if (minor >= CM4000_MAX_DEV)		return -ENODEV;	link = dev_table[minor];	if (link == NULL)		return -ENODEV;	dev = link->priv;	DEBUGP(2, dev, "-> cmm_close(maj/min=%d.%d)\n",	       imajor(inode), minor);	stop_monitor(dev);	ZERO_DEV(dev);	link->open = 0;		/* only one open per device */	wake_up(&dev->devq);	/* socket removed? */	DEBUGP(2, dev, "cmm_close\n");	return 0;}static void cmm_cm4000_release(dev_link_t * link){	struct cm4000_dev *dev = link->priv;	/* dont terminate the monitor, rather rely on	 * close doing that for us.	 */	DEBUGP(3, dev, "-> cmm_cm4000_release\n");	while (link->open) {		printk(KERN_INFO MODULE_NAME ": delaying release until "		       "process has terminated\n");		/* note: don't interrupt us:		 * close the applications which own		 * the devices _first_ !		 */		wait_event(dev->devq, (link->open == 0));	}	/* dev->devq=NULL;	this cannot be zeroed earlier */	DEBUGP(3, dev, "<- cmm_cm4000_release\n");	return;}/*==== Interface to PCMCIA Layer =======================================*/static void cm4000_config(dev_link_t * link, int devno){	client_handle_t handle = link->handle;	struct cm4000_dev *dev;	tuple_t tuple;	cisparse_t parse;	config_info_t conf;	u_char buf[64];	int fail_fn, fail_rc;	int rc;	/* read the config-tuples */	tuple.DesiredTuple = CISTPL_CONFIG;	tuple.Attributes = 0;	tuple.TupleData = buf;	tuple.TupleDataMax = sizeof(buf);	tuple.TupleOffset = 0;	if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) {		fail_fn = GetFirstTuple;		goto cs_failed;	}	if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) {		fail_fn = GetTupleData;		goto cs_failed;	}	if ((fail_rc =	     pcmcia_parse_tuple(handle, &tuple, &parse)) != CS_SUCCESS) {		fail_fn = ParseTuple;		goto cs_failed;	}	if ((fail_rc =	     pcmcia_get_configuration_info(handle, &conf)) != CS_SUCCESS) {		fail_fn = GetConfigurationInfo;		goto cs_failed;	}	link->state |= DEV_CONFIG;	link->conf.ConfigBase = parse.config.base;	link->conf.Present = parse.config.rmask[0];	link->conf.Vcc = conf.Vcc;	link->io.BasePort2 = 0;	link->io.NumPorts2 = 0;	link->io.Attributes2 = 0;	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;	for (rc = pcmcia_get_first_tuple(handle, &tuple);	     rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(handle, &tuple)) {		rc = pcmcia_get_tuple_data(handle, &tuple);		if (rc != CS_SUCCESS)			continue;		rc = pcmcia_parse_tuple(handle, &tuple, &parse);		if (rc != CS_SUCCESS)			continue;		link->conf.ConfigIndex = parse.cftable_entry.index;		if (!parse.cftable_entry.io.nwin)			continue;		/* Get the IOaddr */		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;		link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;		if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))			link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;		if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))			link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;		link->io.IOAddrLines = parse.cftable_entry.io.flags		    & CISTPL_IO_LINES_MASK;		rc = pcmcia_request_io(handle, &link->io);		if (rc == CS_SUCCESS)			break;	/* we are done */	}	if (rc != CS_SUCCESS)		goto cs_release;	link->conf.IntType = 00000002;	if ((fail_rc =	     pcmcia_request_configuration(handle, &link->conf)) != CS_SUCCESS) {		fail_fn = RequestConfiguration;		goto cs_release;	}	dev = link->priv;	sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);	dev->node.major = major;	dev->node.minor = devno;	dev->node.next = NULL;	link->dev = &dev->node;	link->state &= ~DEV_CONFIG_PENDING;	return;cs_failed:	cs_error(handle, fail_fn, fail_rc);cs_release:	cm4000_release(link);	link->state &= ~DEV_CONFIG_PENDING;}static int cm4000_event(event_t event, int priority,			event_callback_args_t *args){	dev_link_t *link;	struct cm4000_dev *dev;	int devno;	link = args->client_data;	dev = link->priv;	DEBUGP(3, dev, "-> cm4000_event\n");	for (devno = 0; devno < CM4000_MAX_DEV; devno++)		if (dev_table[devno] == link)			break;	if (devno == CM4000_MAX_DEV)		return CS_BAD_ADAPTER;	switch (event) {	case CS_EVENT_CARD_INSERTION:		DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n");		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;		cm4000_config(link, devno);		break;	case CS_EVENT_CARD_REMOVAL:		DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n");		link->state &= ~DEV_PRESENT;		stop_monitor(dev);		break;	case CS_EVENT_PM_SUSPEND:		DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND "		      "(fall-through to CS_EVENT_RESET_PHYSICAL)\n");		link->state |= DEV_SUSPEND;		/* fall-through */	case CS_EVENT_RESET_PHYSICAL:		DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n");		if (link->state & DEV_CONFIG) {			DEBUGP(5, dev, "ReleaseConfiguration\n");			pcmcia_release_configuration(link->handle);		}		stop_monitor(dev);		break;	case CS_EVENT_PM_RESUME:		DEBUGP(5, dev, "CS_EVENT_PM_RESUME "		      "(fall-through to CS_EVENT_CARD_RESET)\n");		link->state &= ~DEV_SUSPEND;		/* fall-through */	case CS_EVENT_CARD_RESET:		DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n");		if ((link->state & DEV_CONFIG)) {			DEBUGP(5, dev, "RequestConfiguration\n");			pcmcia_request_configuration(link->handle, &link->conf);		}		if (link->open)			start_monitor(dev);		break;	default:		DEBUGP(5, dev, "unknown event %.2x\n", event);		break;	}	DEBUGP(3, dev, "<- cm4000_event\n");	return CS_SUCCESS;}static void cm4000_release(dev_link_t *link){	cmm_cm4000_release(link->priv);	/* delay release until device closed */	pcmcia_release_configuration(link->handle);	pcmcia_release_io(link->handle, &link->io);}static dev_link_t *cm4000_attach(void){	struct cm4000_dev *dev;	dev_link_t *link;	client_reg_t client_reg;	int i;	for (i = 0; i < CM4000_MAX_DEV; i++)		if (dev_table[i] == NULL)			break;	if (i == CM4000_MAX_DEV) {		printk(KERN_NOTICE MODULE_NAME ": all devices in use\n");		return NULL;	}	/* create a new cm4000_cs device */	dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL);	if (dev == NULL)		return NULL;	link = &dev->link;	link->priv = dev;	link->conf.IntType = INT_MEMORY_AND_IO;	dev_table[i] = link;	/* register with card services */	client_reg.dev_info = &dev_info;	client_reg.EventMask =	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;	client_reg.Version = 0x0210;	client_reg.event_callback_args.client_data = link;	i = pcmcia_register_client(&link->handle, &client_reg);	if (i) {		cs_error(link->handle, RegisterClient, i);		cm4000_detach(link);		return NULL;	}	init_waitqueue_head(&dev->devq);	init_waitqueue_head(&dev->ioq);	init_waitqueue_head(&dev->atrq);	init_waitqueue_head(&dev->readq);	return link;}static void cm4000_detach_by_devno(int devno, dev_link_t * link){	struct cm4000_dev *dev = link->priv;	DEBUGP(3, dev, "-> detach_by_devno(devno=%d)\n", devno);	if (link->state & DEV_CONFIG) {		DEBUGP(5, dev, "device still configured (try to release it)\n");		cm4000_release(link);	}	if (link->handle) {		pcmcia_deregister_client(link->handle);	}	dev_table[devno] = NULL;	kfree(dev);	return;}static void cm4000_detach(dev_link_t * link){	int i;	/* find device */	for (i = 0; i < CM4000_MAX_DEV; i++)		if (dev_table[i] == link)			break;	if (i == CM4000_MAX_DEV)		return;	cm4000_detach_by_devno(i, link);	return;}static struct file_operations cm4000_fops = {	.owner	= THIS_MODULE,	.read	= cmm_read,	.write	= cmm_write,	.ioctl	= cmm_ioctl,	.open	= cmm_open,	.release= cmm_close,};static struct pcmcia_device_id cm4000_ids[] = {	PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002),	PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39),	PCMCIA_DEVICE_NULL,};MODULE_DEVICE_TABLE(pcmcia, cm4000_ids);static struct pcmcia_driver cm4000_driver = {	.owner	  = THIS_MODULE,	.drv	  = {		.name = "cm4000_cs",		},	.attach   = cm4000_attach,	.detach   = cm4000_detach,	.event	  = cm4000_event,	.id_table = cm4000_ids,};static int __init cmm_init(void){	printk(KERN_INFO "%s\n", version);	pcmcia_register_driver(&cm4000_driver);	major = register_chrdev(0, DEVICE_NAME, &cm4000_fops);	if (major < 0) {		printk(KERN_WARNING MODULE_NAME			": could not get major number\n");		return -1;	}	return 0;}static void __exit cmm_exit(void){	int i;	printk(KERN_INFO MODULE_NAME ": unloading\n");	pcmcia_unregister_driver(&cm4000_driver);	for (i = 0; i < CM4000_MAX_DEV; i++)		if (dev_table[i])			cm4000_detach_by_devno(i, dev_table[i]);	unregister_chrdev(major, DEVICE_NAME);};module_init(cmm_init);module_exit(cmm_exit);MODULE_LICENSE("Dual BSD/GPL");

⌨️ 快捷键说明

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