Root/drivers/parport/probe.c

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

Archive Download this file



interactive