daisy.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 666 行 · 第 1/2 页

C
666
字号
/* * IEEE 1284.3 Parallel port daisy chain and multiplexor code *  * Copyright (C) 1999, 2000  Tim Waugh <tim@cyberelk.demon.co.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * ??-12-1998: Initial implementation. * 31-01-1999: Make port-cloning transparent. * 13-02-1999: Move DeviceID technique from parport_probe. * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too. * 22-02-2000: Count devices that are actually detected. * * Any part of this program may be used in documents licensed under * the GNU Free Documentation License, Version 1.1 or any later version * published by the Free Software Foundation. */#include <linux/module.h>#include <linux/parport.h>#include <linux/delay.h>#include <linux/sched.h>#include <asm/current.h>#include <asm/uaccess.h>#undef DEBUG#ifdef DEBUG#define DPRINTK(stuff...) printk (stuff)#else#define DPRINTK(stuff...)#endifstatic struct daisydev {	struct daisydev *next;	struct parport *port;	int daisy;	int devnum;} *topology = NULL;static spinlock_t topology_lock = SPIN_LOCK_UNLOCKED;static int numdevs = 0;/* Forward-declaration of lower-level functions. */static int mux_present (struct parport *port);static int num_mux_ports (struct parport *port);static int select_port (struct parport *port);static int assign_addrs (struct parport *port);/* Add a device to the discovered topology. */static void add_dev (int devnum, struct parport *port, int daisy){	struct daisydev *newdev, **p;	newdev = kmalloc (sizeof (struct daisydev), GFP_KERNEL);	if (newdev) {		newdev->port = port;		newdev->daisy = daisy;		newdev->devnum = devnum;		spin_lock(&topology_lock);		for (p = &topology; *p && (*p)->devnum<devnum; p = &(*p)->next)			;		newdev->next = *p;		*p = newdev;		spin_unlock(&topology_lock);	}}/* Clone a parport (actually, make an alias). */static struct parport *clone_parport (struct parport *real, int muxport){	struct parport *extra = parport_register_port (real->base,						       real->irq,						       real->dma,						       real->ops);	if (extra) {		extra->portnum = real->portnum;		extra->physport = real;		extra->muxport = muxport;		real->slaves[muxport-1] = extra;	}	return extra;}/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. * Return value is number of devices actually detected. */int parport_daisy_init (struct parport *port){	int detected = 0;	char *deviceid;	static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };	int num_ports;	int i;	int last_try = 0;again:	/* Because this is called before any other devices exist,	 * we don't have to claim exclusive access.  */	/* If mux present on normal port, need to create new	 * parports for each extra port. */	if (port->muxport < 0 && mux_present (port) &&	    /* don't be fooled: a mux must have 2 or 4 ports. */	    ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {		/* Leave original as port zero. */		port->muxport = 0;		printk (KERN_INFO			"%s: 1st (default) port of %d-way multiplexor\n",			port->name, num_ports);		for (i = 1; i < num_ports; i++) {			/* Clone the port. */			struct parport *extra = clone_parport (port, i);			if (!extra) {				if (signal_pending (current))					break;				schedule ();				continue;			}			printk (KERN_INFO				"%s: %d%s port of %d-way multiplexor on %s\n",				extra->name, i + 1, th[i + 1], num_ports,				port->name);			/* Analyse that port too.  We won't recurse			   forever because of the 'port->muxport < 0'			   test above. */			parport_daisy_init(extra);		}	}	if (port->muxport >= 0)		select_port (port);	parport_daisy_deselect_all (port);	detected += assign_addrs (port);	/* Count the potential legacy device at the end. */	add_dev (numdevs++, port, -1);	/* Find out the legacy device's IEEE 1284 device ID. */	deviceid = kmalloc (1000, GFP_KERNEL);	if (deviceid) {		if (parport_device_id (numdevs - 1, deviceid, 1000) > 2)			detected++;		kfree (deviceid);	}	if (!detected && !last_try) {		/* No devices were detected.  Perhaps they are in some                   funny state; let's try to reset them and see if                   they wake up. */		parport_daisy_fini (port);		parport_write_control (port, PARPORT_CONTROL_SELECT);		udelay (50);		parport_write_control (port,				       PARPORT_CONTROL_SELECT |				       PARPORT_CONTROL_INIT);		udelay (50);		last_try = 1;		goto again;	}	return detected;}/* Forget about devices on a physical port. */void parport_daisy_fini (struct parport *port){	struct daisydev **p;	spin_lock(&topology_lock);	p = &topology;	while (*p) {		struct daisydev *dev = *p;		if (dev->port != port) {			p = &dev->next;			continue;		}		*p = dev->next;		kfree(dev);	}	/* Gaps in the numbering could be handled better.  How should           someone enumerate through all IEEE1284.3 devices in the           topology?. */	if (!topology) numdevs = 0;	spin_unlock(&topology_lock);	return;}/** *	parport_open - find a device by canonical device number *	@devnum: canonical device number *	@name: name to associate with the device *	@pf: preemption callback *	@kf: kick callback *	@irqf: interrupt handler *	@flags: registration flags *	@handle: driver data * *	This function is similar to parport_register_device(), except *	that it locates a device by its number rather than by the port *	it is attached to.  See parport_find_device() and *	parport_find_class(). * *	All parameters except for @devnum are the same as for *	parport_register_device().  The return value is the same as *	for parport_register_device(). **/struct pardevice *parport_open (int devnum, const char *name,				int (*pf) (void *), void (*kf) (void *),				void (*irqf) (int, void *, struct pt_regs *),				int flags, void *handle){	struct daisydev *p = topology;	struct parport *port;	struct pardevice *dev;	int daisy;	spin_lock(&topology_lock);	while (p && p->devnum != devnum)		p = p->next;	if (!p) {		spin_unlock(&topology_lock);		return NULL;	}	daisy = p->daisy;	port = parport_get_port(p->port);	spin_unlock(&topology_lock);	dev = parport_register_device (port, name, pf, kf,				       irqf, flags, handle);	parport_put_port(port);	if (!dev)		return NULL;	dev->daisy = daisy;	/* Check that there really is a device to select. */	if (daisy >= 0) {		int selected;		parport_claim_or_block (dev);		selected = port->daisy;		parport_release (dev);		if (selected != port->daisy) {			/* No corresponding device. */			parport_unregister_device (dev);			return NULL;		}	}	return dev;}/** *	parport_close - close a device opened with parport_open() *	@dev: device to close * *	This is to parport_open() as parport_unregister_device() is to *	parport_register_device(). **/void parport_close (struct pardevice *dev){	parport_unregister_device (dev);}/** *	parport_device_num - convert device coordinates *	@parport: parallel port number *	@mux: multiplexor port number (-1 for no multiplexor) *	@daisy: daisy chain address (-1 for no daisy chain address) * *	This tries to locate a device on the given parallel port, *	multiplexor port and daisy chain address, and returns its *	device number or -NXIO if no device with those coordinates *	exists. **/int parport_device_num (int parport, int mux, int daisy){	int res = -ENXIO;	struct daisydev *dev;	spin_lock(&topology_lock);	dev = topology;	while (dev && dev->port->portnum != parport &&	       dev->port->muxport != mux && dev->daisy != daisy)		dev = dev->next;	if (dev)		res = dev->devnum;	spin_unlock(&topology_lock);	return res;}/** *	parport_device_coords - convert canonical device number *	@devnum: device number *	@parport: pointer to storage for parallel port number *	@mux: pointer to storage for multiplexor port number *	@daisy: pointer to storage for daisy chain address * *	This function converts a device number into its coordinates in *	terms of which parallel port in the system it is attached to, *	which multiplexor port it is attached to if there is a *	multiplexor on that port, and which daisy chain address it has *	if it is in a daisy chain. * *	The caller must allocate storage for @parport, @mux, and *	@daisy. * *	If there is no device with the specified device number, -ENXIO *	is returned.  Otherwise, the values pointed to by @parport, *	@mux, and @daisy are set to the coordinates of the device, *	with -1 for coordinates with no value. * *	This function is not actually very useful, but this interface *	was suggested by IEEE 1284.3. **/int parport_device_coords (int devnum, int *parport, int *mux, int *daisy)

⌨️ 快捷键说明

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