linux/drivers/parport/probe.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Parallel port device probing code
   4 *
   5 * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
   6 *             Philip Blundell <philb@gnu.org>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/parport.h>
  11#include <linux/ctype.h>
  12#include <linux/string.h>
  13#include <linux/slab.h>
  14#include <linux/uaccess.h>
  15
  16static const struct {
  17        const char *token;
  18        const char *descr;
  19} classes[] = {
  20        { "",            "Legacy device" },
  21        { "PRINTER",     "Printer" },
  22        { "MODEM",       "Modem" },
  23        { "NET",         "Network device" },
  24        { "HDC",         "Hard disk" },
  25        { "PCMCIA",      "PCMCIA" },
  26        { "MEDIA",       "Multimedia device" },
  27        { "FDC",         "Floppy disk" },
  28        { "PORTS",       "Ports" },
  29        { "SCANNER",     "Scanner" },
  30        { "DIGICAM",     "Digital camera" },
  31        { "",            "Unknown device" },
  32        { "",            "Unspecified" },
  33        { "SCSIADAPTER", "SCSI adapter" },
  34        { NULL,          NULL }
  35};
  36
  37static void pretty_print(struct parport *port, int device)
  38{
  39        struct parport_device_info *info = &port->probe_info[device + 1];
  40
  41        printk(KERN_INFO "%s", port->name);
  42
  43        if (device >= 0)
  44                printk (" (addr %d)", device);
  45
  46        printk (": %s", classes[info->class].descr);
  47        if (info->class)
  48                printk(", %s %s", info->mfr, info->model);
  49
  50        printk("\n");
  51}
  52
  53static void parse_data(struct parport *port, int device, char *str)
  54{
  55        char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
  56        char *p = txt, *q;
  57        int guessed_class = PARPORT_CLASS_UNSPEC;
  58        struct parport_device_info *info = &port->probe_info[device + 1];
  59
  60        if (!txt) {
  61                printk(KERN_WARNING "%s probe: memory squeeze\n", port->name);
  62                return;
  63        }
  64        strcpy(txt, str);
  65        while (p) {
  66                char *sep;
  67                q = strchr(p, ';');
  68                if (q) *q = 0;
  69                sep = strchr(p, ':');
  70                if (sep) {
  71                        char *u;
  72                        *(sep++) = 0;
  73                        /* Get rid of trailing blanks */
  74                        u = sep + strlen (sep) - 1;
  75                        while (u >= p && *u == ' ')
  76                                *u-- = '\0';
  77                        u = p;
  78                        while (*u) {
  79                                *u = toupper(*u);
  80                                u++;
  81                        }
  82                        if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
  83                                kfree(info->mfr);
  84                                info->mfr = kstrdup(sep, GFP_KERNEL);
  85                        } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
  86                                kfree(info->model);
  87                                info->model = kstrdup(sep, GFP_KERNEL);
  88                        } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
  89                                int i;
  90
  91                                kfree(info->class_name);
  92                                info->class_name = kstrdup(sep, GFP_KERNEL);
  93                                for (u = sep; *u; u++)
  94                                        *u = toupper(*u);
  95                                for (i = 0; classes[i].token; i++) {
  96                                        if (!strcmp(classes[i].token, sep)) {
  97                                                info->class = i;
  98                                                goto rock_on;
  99                                        }
 100                                }
 101                                printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
 102                                info->class = PARPORT_CLASS_OTHER;
 103                        } else if (!strcmp(p, "CMD") ||
 104                                   !strcmp(p, "COMMAND SET")) {
 105                                kfree(info->cmdset);
 106                                info->cmdset = kstrdup(sep, GFP_KERNEL);
 107                                /* if it speaks printer language, it's
 108                                   probably a printer */
 109                                if (strstr(sep, "PJL") || strstr(sep, "PCL"))
 110                                        guessed_class = PARPORT_CLASS_PRINTER;
 111                        } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
 112                                kfree(info->description);
 113                                info->description = kstrdup(sep, GFP_KERNEL);
 114                        }
 115                }
 116        rock_on:
 117                if (q)
 118                        p = q + 1;
 119                else
 120                        p = NULL;
 121        }
 122
 123        /* If the device didn't tell us its class, maybe we have managed to
 124           guess one from the things it did say. */
 125        if (info->class == PARPORT_CLASS_UNSPEC)
 126                info->class = guessed_class;
 127
 128        pretty_print (port, device);
 129
 130        kfree(txt);
 131}
 132
 133/* Read up to count-1 bytes of device id. Terminate buffer with
 134 * '\0'. Buffer begins with two Device ID length bytes as given by
 135 * device. */
 136static ssize_t parport_read_device_id (struct parport *port, char *buffer,
 137                                       size_t count)
 138{
 139        unsigned char length[2];
 140        unsigned lelen, belen;
 141        size_t idlens[4];
 142        unsigned numidlens;
 143        unsigned current_idlen;
 144        ssize_t retval;
 145        size_t len;
 146
 147        /* First two bytes are MSB,LSB of inclusive length. */
 148        retval = parport_read (port, length, 2);
 149
 150        if (retval < 0)
 151                return retval;
 152        if (retval != 2)
 153                return -EIO;
 154
 155        if (count < 2)
 156                return 0;
 157        memcpy(buffer, length, 2);
 158        len = 2;
 159
 160        /* Some devices wrongly send LE length, and some send it two
 161         * bytes short. Construct a sorted array of lengths to try. */
 162        belen = (length[0] << 8) + length[1];
 163        lelen = (length[1] << 8) + length[0];
 164        idlens[0] = min(belen, lelen);
 165        idlens[1] = idlens[0]+2;
 166        if (belen != lelen) {
 167                int off = 2;
 168                /* Don't try lengths of 0x100 and 0x200 as 1 and 2 */
 169                if (idlens[0] <= 2)
 170                        off = 0;
 171                idlens[off] = max(belen, lelen);
 172                idlens[off+1] = idlens[off]+2;
 173                numidlens = off+2;
 174        }
 175        else {
 176                /* Some devices don't truly implement Device ID, but
 177                 * just return constant nibble forever. This catches
 178                 * also those cases. */
 179                if (idlens[0] == 0 || idlens[0] > 0xFFF) {
 180                        printk (KERN_DEBUG "%s: reported broken Device ID"
 181                                " length of %#zX bytes\n",
 182                                port->name, idlens[0]);
 183                        return -EIO;
 184                }
 185                numidlens = 2;
 186        }
 187
 188        /* Try to respect the given ID length despite all the bugs in
 189         * the ID length. Read according to shortest possible ID
 190         * first. */
 191        for (current_idlen = 0; current_idlen < numidlens; ++current_idlen) {
 192                size_t idlen = idlens[current_idlen];
 193                if (idlen+1 >= count)
 194                        break;
 195
 196                retval = parport_read (port, buffer+len, idlen-len);
 197
 198                if (retval < 0)
 199                        return retval;
 200                len += retval;
 201
 202                if (port->physport->ieee1284.phase != IEEE1284_PH_HBUSY_DAVAIL) {
 203                        if (belen != len) {
 204                                printk (KERN_DEBUG "%s: Device ID was %zd bytes"
 205                                        " while device told it would be %d"
 206                                        " bytes\n",
 207                                        port->name, len, belen);
 208                        }
 209                        goto done;
 210                }
 211
 212                /* This might end reading the Device ID too
 213                 * soon. Hopefully the needed fields were already in
 214                 * the first 256 bytes or so that we must have read so
 215                 * far. */
 216                if (buffer[len-1] == ';') {
 217                        printk (KERN_DEBUG "%s: Device ID reading stopped"
 218                                " before device told data not available. "
 219                                "Current idlen %u of %u, len bytes %02X %02X\n",
 220                                port->name, current_idlen, numidlens,
 221                                length[0], length[1]);
 222                        goto done;
 223                }
 224        }
 225        if (current_idlen < numidlens) {
 226                /* Buffer not large enough, read to end of buffer. */
 227                size_t idlen, len2;
 228                if (len+1 < count) {
 229                        retval = parport_read (port, buffer+len, count-len-1);
 230                        if (retval < 0)
 231                                return retval;
 232                        len += retval;
 233                }
 234                /* Read the whole ID since some devices would not
 235                 * otherwise give back the Device ID from beginning
 236                 * next time when asked. */
 237                idlen = idlens[current_idlen];
 238                len2 = len;
 239                while(len2 < idlen && retval > 0) {
 240                        char tmp[4];
 241                        retval = parport_read (port, tmp,
 242                                               min(sizeof tmp, idlen-len2));
 243                        if (retval < 0)
 244                                return retval;
 245                        len2 += retval;
 246                }
 247        }
 248        /* In addition, there are broken devices out there that don't
 249           even finish off with a semi-colon. We do not need to care
 250           about those at this time. */
 251 done:
 252        buffer[len] = '\0';
 253        return len;
 254}
 255
 256/* Get Std 1284 Device ID. */
 257ssize_t parport_device_id (int devnum, char *buffer, size_t count)
 258{
 259        ssize_t retval = -ENXIO;
 260        struct pardevice *dev = parport_open (devnum, "Device ID probe");
 261        if (!dev)
 262                return -ENXIO;
 263
 264        parport_claim_or_block (dev);
 265
 266        /* Negotiate to compatibility mode, and then to device ID
 267         * mode. (This so that we start form beginning of device ID if
 268         * already in device ID mode.) */
 269        parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
 270        retval = parport_negotiate (dev->port,
 271                                    IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
 272
 273        if (!retval) {
 274                retval = parport_read_device_id (dev->port, buffer, count);
 275                parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
 276                if (retval > 2)
 277                        parse_data (dev->port, dev->daisy, buffer+2);
 278        }
 279
 280        parport_release (dev);
 281        parport_close (dev);
 282        return retval;
 283}
 284