Hello,

ioctl(LPGETSTATUS) is known to put the status into  an  int.  The  usblp
driver has a problem in this area as it does not put it into an int  but
into a char. Let's see :

from drivers/char/lp.c : lp_ioctl :
    int status
    copy_to_user((int *) arg, &status, sizeof(int))

from drivers/usb/printer.c : usblp_ioctl :
    unsigned char status;
    copy_to_user ((unsigned char *)arg, &status, 1)

Even though in  most  cases  it  can  work  unnoticed  on  little-endian
machines ;o), it's broken on non-little-endian machines (I got bitten on
PPC).

Attached are patches to fix this issue. These  are  against  2.4.18  and
2.5.21 (untested), upported from 2.4.12 (with 2.4.18 usb stack) which is
the one I've successfully tested. It  works  for  me  on  PPC  now  (I'm
printing  on  USB  Canon  printers  like   the   S100   using   in-house
hardware...). Feedback is welcome,


Flavien.
--- linux-2.4.18/drivers/usb/printer.c  Wed Oct 10 00:15:02 2001
+++ linux-2.4.18.fl/drivers/usb/printer.c       Wed Jun 12 19:03:01 2002
@@ -295,7 +295,8 @@
 {
        struct usblp *usblp = file->private_data;
        int length, err;
-       unsigned char status;
+       unsigned char lpstatus;
+       int status;
        int retval = 0;
 
        down (&usblp->sem);
@@ -349,12 +350,13 @@
                switch (cmd) {
 
                        case LPGETSTATUS:
-                               if (usblp_read_status(usblp, &status)) {
+                               if (usblp_read_status(usblp, &lpstatus)) {
                                        err("usblp%d: failed reading printer status", 
usblp->minor);
                                        retval = -EIO;
                                        goto done;
                                }
-                               if (copy_to_user ((unsigned char *)arg, &status, 1))
+                               status = lpstatus;
+                               if (copy_to_user ((int *)arg, &status, sizeof(int)))
                                        retval = -EFAULT;
                                break;
 
--- linux-2.5.21/drivers/usb/class/printer.c    Sun Jun  9 07:27:45 2002
+++ linux-2.5.21.fl/drivers/usb/class/printer.c Wed Jun 12 16:08:08 2002
@@ -418,7 +418,8 @@
 {
        struct usblp *usblp = file->private_data;
        int length, err, i;
-       unsigned char status, newChannel;
+       unsigned char lpstatus, newChannel;
+       int status;
        int twoints[2];
        int retval = 0;
 
@@ -569,12 +570,13 @@
                switch (cmd) {
 
                        case LPGETSTATUS:
-                               if (usblp_read_status(usblp, &status)) {
+                               if (usblp_read_status(usblp, &lpstatus)) {
                                        err("usblp%d: failed reading printer status", 
usblp->minor);
                                        retval = -EIO;
                                        goto done;
                                }
-                               if (copy_to_user ((unsigned char *)arg, &status, 1))
+                               status = lpstatus;
+                               if (copy_to_user ((int *)arg, &status, sizeof(int)))
                                        retval = -EFAULT;
                                break;
 

Reply via email to