[haiku-commits] r36115 - haiku/trunk/src/add-ons/print/transports/usb_port

Author: ithamar
Date: 2010-04-10 19:12:31 +0200 (Sat, 10 Apr 2010)
New Revision: 36115
Changeset: http://dev.haiku-os.org/changeset/36115/haiku

Modified:
   haiku/trunk/src/add-ons/print/transports/usb_port/Jamfile
   haiku/trunk/src/add-ons/print/transports/usb_port/USBTransport.cpp
Log:
* Switch to using USBKit instead of usb_printer kernel driver
* Implement new transport id/name listing



Modified: haiku/trunk/src/add-ons/print/transports/usb_port/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/print/transports/usb_port/Jamfile   2010-04-10 
16:36:48 UTC (rev 36114)
+++ haiku/trunk/src/add-ons/print/transports/usb_port/Jamfile   2010-04-10 
17:12:31 UTC (rev 36115)
@@ -2,14 +2,14 @@
 
 SetSubDirSupportedPlatformsBeOSCompatible ;
 
-UsePrivateHeaders print ;
+UsePrivateHeaders shared print ;
 
 SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits print ] ;
 
 Addon USB\ Port :
        USBTransport.cpp
        PrintTransportAddOn.cpp
-       : be $(TARGET_LIBSUPC++)
+       : libshared.a libdevice.so be $(TARGET_LIBSUPC++)
 ;
 
 Package haiku-printingkit-cvs :

Modified: haiku/trunk/src/add-ons/print/transports/usb_port/USBTransport.cpp
===================================================================
--- haiku/trunk/src/add-ons/print/transports/usb_port/USBTransport.cpp  
2010-04-10 16:36:48 UTC (rev 36114)
+++ haiku/trunk/src/add-ons/print/transports/usb_port/USBTransport.cpp  
2010-04-10 17:12:31 UTC (rev 36115)
@@ -1,67 +1,221 @@
-/*****************************************************************************/
-// USB port transport add-on,
-// changes by Andreas Benzler, Philippe Houdoin
-//
-// Original from Parallel 
-// port transport add-on.
-//
-// Author
-//   Michael Pfeiffer
-// 
-// This application and all source files used in its construction, except 
-// where noted, are licensed under the MIT License, and have been written 
-// and are:
-//
-// Copyright (c) 2001-2004 OpenBeOS Project
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense, 
-// and/or sell copies of the Software, and to permit persons to whom the 
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included 
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
-// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-/*****************************************************************************/
+/*
+ * Copyright 2001-2010 Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Originally written based on Parallel port addon by Michael Pfeiffer,
+ * changes by Andreas Benzler, Philippe Houdoin
+ * Rewritten to use the USBKit by Ithamar R. Adema.
+ *   (Using code from usb_printer.cpp by Michael Lotz)
+ *
+ * Authors:
+ *             Ithamar R. Adema, <ithamar.adema@xxxxxxxxxxxxxxxx>
+ *             Michael Pfeiffer,
+ *             Andreas Benzler,
+ *             Philippe Houdoin,
+ */
 
+#include "PrintTransportAddOn.h"
 
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
+#include <USBKit.h>
+#include <String.h>
 
-#include <StorageKit.h>
-#include <SupportKit.h>
+#include <HashString.h>
+#include <HashMap.h>
 
-#include <USB_printer.h>
+#define PRINTER_INTERFACE_CLASS                0x07
+#define PRINTER_INTERFACE_SUBCLASS     0x01
 
-#include "PrintTransportAddOn.h"
+// printer interface types
+#define PIT_UNIDIRECTIONAL             0x01
+#define PIT_BIDIRECTIONAL              0x02
+#define PIT_1284_4_COMPATIBLE          0x03
+#define PIT_VENDOR_SPECIFIC            0xff
 
+class USBPrinter
+{
+public:
+       USBPrinter(const BString& id, const BString& name,
+               const BUSBInterface *intf, const BUSBEndpoint* in, const 
BUSBEndpoint* out);
 
+       ssize_t Write(const void *buf, size_t size);
+       ssize_t Read(void *buf, size_t size);
+
+       const BUSBInterface     *fInterface;
+       const BUSBEndpoint      *fOut;
+       const BUSBEndpoint      *fIn;
+       BString                         fName;
+       BString                         fID;
+};
+
+
+class USBPrinterRoster : public BUSBRoster {
+public:
+       USBPrinterRoster();
+
+       status_t DeviceAdded(BUSBDevice* dev);
+       void DeviceRemoved(BUSBDevice* dev);
+
+       USBPrinter *Printer(const BString& key);
+
+       status_t ListPrinters(BMessage *msg);
+private:
+       typedef HashMap<HashString,USBPrinter*> PrinterMap;
+       PrinterMap fPrinters;
+};
+
+
 class USBTransport : public BDataIO 
 {      
 public:
        USBTransport(BDirectory *printer, BMessage *msg);
        ~USBTransport();
 
-       status_t InitCheck() { return fFile > -1 ? B_OK : B_ERROR; };
+       status_t InitCheck() { return fPrinter ? B_OK : B_ERROR; };
 
        ssize_t Read(void *buffer, size_t size);
        ssize_t Write(const void *buffer, size_t size);
 
 private:
-       int fFile;
+       USBPrinter *fPrinter;
 };
 
 
+// Set transport_features so we stay loaded
+uint32 transport_features = B_TRANSPORT_IS_HOTPLUG;
+
+USBPrinterRoster gUSBPrinterRoster;
+
+USBPrinterRoster::USBPrinterRoster()
+{
+       Start();
+}
+
+USBPrinter *USBPrinterRoster::Printer(const BString& key)
+{
+       if (fPrinters.ContainsKey(key.String()))
+               return fPrinters.Get(key.String());
+
+       return NULL;
+}
+
+status_t USBPrinterRoster::DeviceAdded(BUSBDevice* dev)
+{
+       const BUSBConfiguration *cfg = dev->ActiveConfiguration();
+       const BUSBEndpoint *in = NULL, *out = NULL;
+       const BUSBInterface *printer = NULL;
+
+       // Try to find a working printer interface in this device
+       if (cfg) {
+               for (uint32 idx=0; printer == NULL && idx < 
cfg->CountInterfaces(); idx++) {
+                       const BUSBInterface *intf=cfg->InterfaceAt(idx);
+                       if (intf->Class() == PRINTER_INTERFACE_CLASS &&
+                               intf->Subclass() == PRINTER_INTERFACE_SUBCLASS 
&&
+                               (intf->Protocol() == PIT_UNIDIRECTIONAL ||
+                                intf->Protocol() == PIT_BIDIRECTIONAL ||
+                                intf->Protocol() == PIT_1284_4_COMPATIBLE)) {
+                               // Found a usable Printer interface!
+                               for (uint32 eptidx=0; eptidx < 
intf->CountEndpoints(); eptidx++) {
+                                       const BUSBEndpoint *ept = 
intf->EndpointAt(eptidx);
+                                       if (!ept->IsBulk())
+                                               continue;
+
+                                       if (ept->IsInput())
+                                               in = ept;
+                                       else if (ept->IsOutput())
+                                               out = ept;
+
+                                       if (!in || !out)
+                                               continue;
+
+                                       printer = intf;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if (printer != NULL) {
+               // We found a working printer interface, lets determine a 
unique ID
+               //  for it now, and a user identification for display in the 
Printers
+               //  preference.
+               BString port_id = dev->SerialNumberString();
+               if (!port_id.Length()) {
+                       // No persistent unique ID available, use the 
vendor/product
+                       //   ID for now. This will be unique as long as no two 
similar
+                       //   devices are attached.
+                       port_id << dev->VendorID() << "/" << dev->ProductID();
+               }
+
+               BString port_name = dev->ManufacturerString();
+               if (port_name.Length())
+                       port_name << " ";
+               port_name << dev->ProductString();
+
+               //TODO: Do we want to use usb.ids to find proper name if strings
+               //        are not supplied by USB?
+
+               fPrinters.Put(port_id.String(), new USBPrinter(port_id, 
port_name,
+                       printer, in, out));
+       }
+
+       return B_OK;
+}
+
+void USBPrinterRoster::DeviceRemoved(BUSBDevice* dev)
+{
+       PrinterMap::Iterator iterator = fPrinters.GetIterator();
+       while (iterator.HasNext()) {
+               const PrinterMap::Entry& entry = iterator.Next();
+               // If the device is in the list, remove it
+               if (entry.value->fInterface->Device() == dev) {
+                       fPrinters.Remove(entry.key);
+                       delete entry.value;
+                       break;
+               }
+       }
+}
+
+
+status_t USBPrinterRoster::ListPrinters(BMessage* msg)
+{
+       PrinterMap::Iterator iterator = fPrinters.GetIterator();
+       while (iterator.HasNext()) {
+               const PrinterMap::Entry& entry = iterator.Next();
+               msg->AddString("port_id", entry.value->fID);
+               msg->AddString("port_name", entry.value->fName);
+       }
+
+       return B_OK;
+}
+
+
+USBPrinter::USBPrinter(const BString& id, const BString& name,
+       const BUSBInterface *intf, const BUSBEndpoint* in, const BUSBEndpoint* 
out)
+       : fInterface(intf), fOut(out), fIn(in), fName(name), fID(id)
+{
+}
+
+
+//TODO: see usb_printer.cpp for error handling during read/write!
+ssize_t USBPrinter::Write(const void *buf, size_t size)
+{
+       if (!buf || size <= 0)
+               return B_BAD_VALUE;
+
+       // NOTE: we can safely cast below as we're sending data _out_
+       return fOut->BulkTransfer((void*)buf, size);
+}
+
+
+ssize_t USBPrinter::Read(void *buf, size_t size)
+{
+       if (!buf || size <= 0)
+               return B_BAD_VALUE;
+
+       return fIn->BulkTransfer(buf, size);
+}
+
+
 // Implementation of transport add-on interface
 
 BDataIO * 
@@ -75,99 +229,48 @@
        return NULL;
 }
 
+// List detected printers
 status_t list_transport_ports(BMessage* msg)
 {
-       BDirectory dir("/dev/printer/usb");
-       status_t rc;
-
-       if ((rc=dir.InitCheck()) != B_OK)
-               return rc;
-
-       if ((rc=dir.Rewind()) != B_OK)
-               return rc;
-
-       entry_ref ref;
-       while(dir.GetNextRef(&ref) == B_OK)
-               msg->AddString("port_id", ref.name);
-
-       return B_OK;
+       return gUSBPrinterRoster.ListPrinters(msg);
 }
 
-
 // Implementation of USBTransport
-
 USBTransport::USBTransport(BDirectory *printer, BMessage *msg) 
-       : fFile(-1)
+       : fPrinter(NULL)
 {
-       char device_id[USB_PRINTER_DEVICE_ID_LENGTH + 1];
-       char name[USB_PRINTER_DEVICE_ID_LENGTH + 1];
-       char *desc;
-       char *value;
-       int ret;
-       bool bidirectional = true;
-       char *next_token;
-       
-       // We support only one USB printer, so does BeOS R5.
-       fFile = open("/dev/printer/usb/0", O_RDWR | O_EXCL | O_BINARY, 0);
-       if (fFile < 0) {
-               // Try unidirectional access mode
-               bidirectional = false;
-               fFile = open("/dev/printer/usb/0", O_WRONLY | O_EXCL | 
O_BINARY, 0);
-       }
-       
-       if (fFile < 0)
+       BString key;
+
+       if (printer->ReadAttrString("transport_address", &key) < 0)
                return;
-       
-       // Get printer's DEVICE ID string
-       ret = ioctl(fFile, USB_PRINTER_GET_DEVICE_ID, device_id, 
sizeof(device_id));
-       if (ret < 0) {
-               close(fFile);
-               fFile = -1;
+
+       fPrinter = gUSBPrinterRoster.Printer(key.String());
+       if (!fPrinter)
                return;
-       }
-       
-       if (! msg)
-               // Caller don't care about transport init message output 
content...
+
+       // If caller doesn't care...
+       if (!msg)
                return;
-       
+
        // Fill up the message
        msg->what = 'okok';
-       
-       msg->AddBool("bidirectional", bidirectional);
-       msg->AddString("device_id", device_id);
-
-       // parse and split the device_id string into separate parameters
-       desc = strtok_r(device_id, ":", &next_token);   
-       while (desc) {
-               snprintf(name, sizeof(name), "DEVID:%s", desc);
-               value = strtok_r(NULL, ";", &next_token);
-               if (!value)
-                       break;
-               msg->AddString(name, value);
-               
-               // next device descriptor
-               desc = strtok_r(NULL, ":", &next_token);        
-       }
 }
 
 
 USBTransport::~USBTransport()
 {
-       if (fFile > -1)
-               close(fFile);
 }
 
 
 ssize_t
 USBTransport::Read(void *buffer, size_t size)
 {
-       return read(fFile, buffer, size);
+       return fPrinter ? fPrinter->Read(buffer, size) : B_ERROR;
 }
 
 
 ssize_t
 USBTransport::Write(const void *buffer, size_t size)
 {
-       return write(fFile, buffer, size);
+       return fPrinter ? fPrinter->Write(buffer, size) : B_ERROR;
 }
-


Other related posts: