Commit b484a748 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] parport: slave port cleanups

	references to slave ports of mux added to struct parport.
parport_daisy_init() doesn't go through parport_announce_port() for mux
slaves anymore; parport_annouce_port() deals with found ones itself.
Error handling sanitized, races on unregistration fixed.
parent eda96df0
......@@ -80,6 +80,7 @@ static struct parport *clone_parport (struct parport *real, int muxport)
extra->portnum = real->portnum;
extra->physport = real;
extra->muxport = muxport;
real->slaves[muxport-1] = extra;
}
return extra;
......@@ -94,7 +95,9 @@ int parport_daisy_init (struct parport *port)
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. */
......@@ -127,7 +130,7 @@ int parport_daisy_init (struct parport *port)
/* Analyse that port too. We won't recurse
forever because of the 'port->muxport < 0'
test above. */
parport_announce_port (extra);
parport_daisy_init(extra);
}
}
......@@ -149,6 +152,21 @@ int parport_daisy_init (struct parport *port)
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;
}
......
......@@ -413,22 +413,11 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
void parport_announce_port (struct parport *port)
{
int i;
#ifdef CONFIG_PARPORT_1284
/* Analyse the IEEE1284.3 topology of the port. */
if (parport_daisy_init (port) == 0) {
/* 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);
parport_daisy_init (port);
}
parport_daisy_init(port);
#endif
down(&registration_lock);
......@@ -447,13 +436,48 @@ void parport_announce_port (struct parport *port)
portlist_tail = port;
if (!portlist)
portlist = port;
for (i = 1; i < 3; i++) {
struct parport *slave = port->slaves[i-1];
if (slave) {
portlist_tail->next = slave;
portlist_tail = slave;
}
}
spin_unlock_irq(&parportlist_lock);
/* Let drivers know that a new port has arrived. */
/* Let drivers know that new port(s) has arrived. */
attach_driver_chain (port);
for (i = 1; i < 3; i++) {
struct parport *slave = port->slaves[i-1];
if (slave)
attach_driver_chain(slave);
}
up(&registration_lock);
}
static void unlink_from_list(struct parport *port)
{
struct parport *p;
spin_lock(&parportlist_lock);
/* We are protected from other people changing the list, but
* they can still see it (using parport_enumerate). So be
* careful about the order of writes.. */
if (portlist == port) {
if ((portlist = port->next) == NULL)
portlist_tail = NULL;
} else {
for (p = portlist; (p != NULL) && (p->next != port);
p=p->next);
if (p) {
if ((p->next = port->next) == NULL)
portlist_tail = p;
}
else printk (KERN_WARNING
"%s not found in port list!\n", port->name);
}
spin_unlock(&parportlist_lock);
}
/**
* parport_unregister_port - deregister a parallel port
* @port: parallel port to deregister
......@@ -475,41 +499,41 @@ void parport_announce_port (struct parport *port)
void parport_unregister_port(struct parport *port)
{
struct parport *p;
int i;
down(&registration_lock);
port->ops = &dead_ops;
/* Spread the word. */
detach_driver_chain (port);
#ifdef CONFIG_PARPORT_1284
/* Forget the IEEE1284.3 topology of the port. */
parport_daisy_fini (port);
parport_daisy_fini(port);
for (i = 1; i < 3; i++) {
struct parport *slave = port->slaves[i-1];
if (!slave)
continue;
detach_driver_chain(slave);
parport_daisy_fini(slave);
}
#endif
spin_lock(&parportlist_lock);
/* We are protected from other people changing the list, but
* they can still see it (using parport_enumerate). So be
* careful about the order of writes.. */
if (portlist == port) {
if ((portlist = port->next) == NULL)
portlist_tail = NULL;
} else {
for (p = portlist; (p != NULL) && (p->next != port);
p=p->next);
if (p) {
if ((p->next = port->next) == NULL)
portlist_tail = p;
}
else printk (KERN_WARNING
"%s not found in port list!\n", port->name);
port->ops = &dead_ops;
unlink_from_list(port);
for (i = 1; i < 3; i++) {
struct parport *slave = port->slaves[i-1];
if (slave)
unlink_from_list(slave);
}
spin_unlock(&parportlist_lock);
up(&registration_lock);
/* Yes, parport_enumerate _is_ unsafe. Don't use it. */
for (i = 1; i < 3; i++) {
struct parport *slave = port->slaves[i-1];
if (slave)
parport_put_port(slave);
}
parport_put_port (port);
}
......
......@@ -313,6 +313,7 @@ struct parport {
atomic_t ref_count;
struct list_head full_list;
struct parport *slaves[3];
};
#define DEFAULT_SPIN_TIME 500 /* us */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment