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/string.h>
  12#include <linux/string_helpers.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        pr_info("%s", port->name);
  42
  43        if (device >= 0)
  44                pr_cont(" (addr %d)", device);
  45
  46        pr_cont(": %s", classes[info->class].descr);
  47        if (info->class)
  48                pr_cont(", %s %s", info->mfr, info->model);
  49
  50        pr_cont("\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                pr_warn("%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                        string_upper(p, p);
  78                        if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
  79                                kfree(info->mfr);
  80                                info->mfr = kstrdup(sep, GFP_KERNEL);
  81                        } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
  82                                kfree(info->model);
  83                                info->model = kstrdup(sep, GFP_KERNEL);
  84                        } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
  85                                int i;
  86
  87                                kfree(info->class_name);
  88                                info->class_name = kstrdup(sep, GFP_KERNEL);
  89                                string_upper(sep, sep);
  90                                for (i = 0; classes[i].token; i++) {
  91                                        if (!strcmp(classes[i].token, sep)) {
  92                                                info->class = i;
  93                                                goto rock_on;
  94                                        }
  95                                }
  96                                pr_warn("%s probe: warning, class '%s' not understood\n",
  97                                        port->name, sep);
  98                                info->class = PARPORT_CLASS_OTHER;
  99                        } else if (!strcmp(p, "CMD") ||
 100                                   !strcmp(p, "COMMAND SET")) {
 101                                kfree(info->cmdset);
 102                                info->cmdset = kstrdup(sep, GFP_KERNEL);
 103                                /* if it speaks printer language, it's
 104                                   probably a printer */
 105                                if (strstr(sep, "PJL") || strstr(sep, "PCL"))
 106                                        guessed_class = PARPORT_CLASS_PRINTER;
 107                        } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
 108                                kfree(info->description);
 109                                info->description = kstrdup(sep, GFP_KERNEL);
 110                        }
 111                }
 112        rock_on:
 113                if (q)
 114                        p = q + 1;
 115                else
 116                        p = NULL;
 117        }
 118
 119        /* If the device didn't tell us its class, maybe we have managed to
 120           guess one from the things it did say. */
 121        if (info->class == PARPORT_CLASS_UNSPEC)
 122                info->class = guessed_class;
 123
 124        pretty_print (port, device);
 125
 126        kfree(txt);
 127}
 128
 129/* Read up to count-1 bytes of device id. Terminate buffer with
 130 * '\0'. Buffer begins with two Device ID length bytes as given by
 131 * device. */
 132static ssize_t parport_read_device_id (struct parport *port, char *buffer,
 133                                       size_t count)
 134{
 135        unsigned char length[2];
 136        unsigned lelen, belen;
 137        size_t idlens[4];
 138        unsigned numidlens;
 139        unsigned current_idlen;
 140        ssize_t retval;
 141        size_t len;
 142
 143        /* First two bytes are MSB,LSB of inclusive length. */
 144        retval = parport_read (port, length, 2);
 145
 146        if (retval < 0)
 147                return retval;
 148        if (retval != 2)
 149                return -EIO;
 150
 151        if (count < 2)
 152                return 0;
 153        memcpy(buffer, length, 2);
 154        len = 2;
 155
 156        /* Some devices wrongly send LE length, and some send it two
 157         * bytes short. Construct a sorted array of lengths to try. */
 158        belen = (length[0] << 8) + length[1];
 159        lelen = (length[1] << 8) + length[0];
 160        idlens[0] = min(belen, lelen);
 161        idlens[1] = idlens[0]+2;
 162        if (belen != lelen) {
 163                int off = 2;
 164                /* Don't try lengths of 0x100 and 0x200 as 1 and 2 */
 165                if (idlens[0] <= 2)
 166                        off = 0;
 167                idlens[off] = max(belen, lelen);
 168                idlens[off+1] = idlens[off]+2;
 169                numidlens = off+2;
 170        }
 171        else {
 172                /* Some devices don't truly implement Device ID, but
 173                 * just return constant nibble forever. This catches
 174                 * also those cases. */
 175                if (idlens[0] == 0 || idlens[0] > 0xFFF) {
 176                        printk(KERN_DEBUG "%s: reported broken Device ID length of %#zX bytes\n",
 177                               port->name, idlens[0]);
 178                        return -EIO;
 179                }
 180                numidlens = 2;
 181        }
 182
 183        /* Try to respect the given ID length despite all the bugs in
 184         * the ID length. Read according to shortest possible ID
 185         * first. */
 186        for (current_idlen = 0; current_idlen < numidlens; ++current_idlen) {
 187                size_t idlen = idlens[current_idlen];
 188                if (idlen+1 >= count)
 189                        break;
 190
 191                retval = parport_read (port, buffer+len, idlen-len);
 192
 193                if (retval < 0)
 194                        return retval;
 195                len += retval;
 196
 197                if (port->physport->ieee1284.phase != IEEE1284_PH_HBUSY_DAVAIL) {
 198                        if (belen != len) {
 199                                printk(KERN_DEBUG "%s: Device ID was %zd bytes while device told it would be %d bytes\n",
 200                                       port->name, len, belen);
 201                        }
 202                        goto done;
 203                }
 204
 205                /* This might end reading the Device ID too
 206                 * soon. Hopefully the needed fields were already in
 207                 * the first 256 bytes or so that we must have read so
 208                 * far. */
 209                if (buffer[len-1] == ';') {
 210                        printk(KERN_DEBUG "%s: Device ID reading stopped before device told data not available. Current idlen %u of %u, len bytes %02X %02X\n",
 211                               port->name, current_idlen, numidlens,
 212                               length[0], length[1]);
 213                        goto done;
 214                }
 215        }
 216        if (current_idlen < numidlens) {
 217                /* Buffer not large enough, read to end of buffer. */
 218                size_t idlen, len2;
 219                if (len+1 < count) {
 220                        retval = parport_read (port, buffer+len, count-len-1);
 221                        if (retval < 0)
 222                                return retval;
 223                        len += retval;
 224                }
 225                /* Read the whole ID since some devices would not
 226                 * otherwise give back the Device ID from beginning
 227                 * next time when asked. */
 228                idlen = idlens[current_idlen];
 229                len2 = len;
 230                while(len2 < idlen && retval > 0) {
 231                        char tmp[4];
 232                        retval = parport_read (port, tmp,
 233                                               min(sizeof tmp, idlen-len2));
 234                        if (retval < 0)
 235                                return retval;
 236                        len2 += retval;
 237                }
 238        }
 239        /* In addition, there are broken devices out there that don't
 240           even finish off with a semi-colon. We do not need to care
 241           about those at this time. */
 242 done:
 243        buffer[len] = '\0';
 244        return len;
 245}
 246
 247/* Get Std 1284 Device ID. */
 248ssize_t parport_device_id (int devnum, char *buffer, size_t count)
 249{
 250        ssize_t retval = -ENXIO;
 251        struct pardevice *dev = parport_open(devnum, daisy_dev_name);
 252        if (!dev)
 253                return -ENXIO;
 254
 255        parport_claim_or_block (dev);
 256
 257        /* Negotiate to compatibility mode, and then to device ID
 258         * mode. (This so that we start form beginning of device ID if
 259         * already in device ID mode.) */
 260        parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
 261        retval = parport_negotiate (dev->port,
 262                                    IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
 263
 264        if (!retval) {
 265                retval = parport_read_device_id (dev->port, buffer, count);
 266                parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
 267                if (retval > 2)
 268                        parse_data (dev->port, dev->daisy, buffer+2);
 269        }
 270
 271        parport_release (dev);
 272        parport_close (dev);
 273        return retval;
 274}
 275