1
linux/drivers/parport/probe.c
Paulo Marques 543537bd92 [PATCH] create a kstrdup library function
This patch creates a new kstrdup library function and changes the "local"
implementations in several places to use this function.

Most of the changes come from the sound and net subsystems.  The sound part
had already been acknowledged by Takashi Iwai and the net part by David S.
Miller.

I left UML alone for now because I would need more time to read the code
carefully before making changes there.

Signed-off-by: Paulo Marques <pmarques@grupopie.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-23 09:45:18 -07:00

217 lines
5.8 KiB
C

/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
* Parallel port device probing code
*
* Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
* Philip Blundell <philb@gnu.org>
*/
#include <linux/module.h>
#include <linux/parport.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <asm/uaccess.h>
static struct {
char *token;
char *descr;
} classes[] = {
{ "", "Legacy device" },
{ "PRINTER", "Printer" },
{ "MODEM", "Modem" },
{ "NET", "Network device" },
{ "HDC", "Hard disk" },
{ "PCMCIA", "PCMCIA" },
{ "MEDIA", "Multimedia device" },
{ "FDC", "Floppy disk" },
{ "PORTS", "Ports" },
{ "SCANNER", "Scanner" },
{ "DIGICAM", "Digital camera" },
{ "", "Unknown device" },
{ "", "Unspecified" },
{ "SCSIADAPTER", "SCSI adapter" },
{ NULL, NULL }
};
static void pretty_print(struct parport *port, int device)
{
struct parport_device_info *info = &port->probe_info[device + 1];
printk(KERN_INFO "%s", port->name);
if (device >= 0)
printk (" (addr %d)", device);
printk (": %s", classes[info->class].descr);
if (info->class)
printk(", %s %s", info->mfr, info->model);
printk("\n");
}
static void parse_data(struct parport *port, int device, char *str)
{
char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
char *p = txt, *q;
int guessed_class = PARPORT_CLASS_UNSPEC;
struct parport_device_info *info = &port->probe_info[device + 1];
if (!txt) {
printk(KERN_WARNING "%s probe: memory squeeze\n", port->name);
return;
}
strcpy(txt, str);
while (p) {
char *sep;
q = strchr(p, ';');
if (q) *q = 0;
sep = strchr(p, ':');
if (sep) {
char *u;
*(sep++) = 0;
/* Get rid of trailing blanks */
u = sep + strlen (sep) - 1;
while (u >= p && *u == ' ')
*u-- = '\0';
u = p;
while (*u) {
*u = toupper(*u);
u++;
}
if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
if (info->mfr)
kfree (info->mfr);
info->mfr = kstrdup(sep, GFP_KERNEL);
} else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
if (info->model)
kfree (info->model);
info->model = kstrdup(sep, GFP_KERNEL);
} else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
int i;
if (info->class_name)
kfree (info->class_name);
info->class_name = kstrdup(sep, GFP_KERNEL);
for (u = sep; *u; u++)
*u = toupper(*u);
for (i = 0; classes[i].token; i++) {
if (!strcmp(classes[i].token, sep)) {
info->class = i;
goto rock_on;
}
}
printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
info->class = PARPORT_CLASS_OTHER;
} else if (!strcmp(p, "CMD") ||
!strcmp(p, "COMMAND SET")) {
if (info->cmdset)
kfree (info->cmdset);
info->cmdset = kstrdup(sep, GFP_KERNEL);
/* if it speaks printer language, it's
probably a printer */
if (strstr(sep, "PJL") || strstr(sep, "PCL"))
guessed_class = PARPORT_CLASS_PRINTER;
} else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
if (info->description)
kfree (info->description);
info->description = kstrdup(sep, GFP_KERNEL);
}
}
rock_on:
if (q) p = q+1; else p=NULL;
}
/* If the device didn't tell us its class, maybe we have managed to
guess one from the things it did say. */
if (info->class == PARPORT_CLASS_UNSPEC)
info->class = guessed_class;
pretty_print (port, device);
kfree(txt);
}
/* Get Std 1284 Device ID. */
ssize_t parport_device_id (int devnum, char *buffer, size_t len)
{
ssize_t retval = -ENXIO;
struct pardevice *dev = parport_open (devnum, "Device ID probe",
NULL, NULL, NULL, 0, NULL);
if (!dev)
return -ENXIO;
parport_claim_or_block (dev);
/* Negotiate to compatibility mode, and then to device ID mode.
* (This is in case we are already in device ID mode.) */
parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
retval = parport_negotiate (dev->port,
IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
if (!retval) {
int idlen;
unsigned char length[2];
/* First two bytes are MSB,LSB of inclusive length. */
retval = parport_read (dev->port, length, 2);
if (retval != 2) goto end_id;
idlen = (length[0] << 8) + length[1] - 2;
/*
* Check if the caller-allocated buffer is large enough
* otherwise bail out or there will be an at least off by one.
*/
if (idlen + 1 < len)
len = idlen;
else {
retval = -EINVAL;
goto out;
}
retval = parport_read (dev->port, buffer, len);
if (retval != len)
printk (KERN_DEBUG "%s: only read %Zd of %Zd ID bytes\n",
dev->port->name, retval,
len);
/* Some printer manufacturers mistakenly believe that
the length field is supposed to be _exclusive_.
In addition, there are broken devices out there
that don't even finish off with a semi-colon. */
if (buffer[len - 1] != ';') {
ssize_t diff;
diff = parport_read (dev->port, buffer + len, 2);
retval += diff;
if (diff)
printk (KERN_DEBUG
"%s: device reported incorrect "
"length field (%d, should be %Zd)\n",
dev->port->name, idlen, retval);
else {
/* One semi-colon short of a device ID. */
buffer[len++] = ';';
printk (KERN_DEBUG "%s: faking semi-colon\n",
dev->port->name);
/* If we get here, I don't think we
need to worry about the possible
standard violation of having read
more than we were told to. The
device is non-compliant anyhow. */
}
}
end_id:
buffer[len] = '\0';
parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
}
if (retval > 2)
parse_data (dev->port, dev->daisy, buffer);
out:
parport_release (dev);
parport_close (dev);
return retval;
}