Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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