From c52f7982c9276b5441b601229605e59b39306778 Mon Sep 17 00:00:00 2001 From: "Ithamar R. Adema" Date: Sat, 10 Apr 2010 17:12:31 +0000 Subject: [PATCH] * Switch to using USBKit instead of usb_printer kernel driver * Implement new transport id/name listing git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36115 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/print/transports/usb_port/Jamfile | 4 +- .../transports/usb_port/USBTransport.cpp | 327 ++++++++++++------ 2 files changed, 217 insertions(+), 114 deletions(-) diff --git a/src/add-ons/print/transports/usb_port/Jamfile b/src/add-ons/print/transports/usb_port/Jamfile index 276f4e43ae..7f67abeae7 100644 --- a/src/add-ons/print/transports/usb_port/Jamfile +++ b/src/add-ons/print/transports/usb_port/Jamfile @@ -2,14 +2,14 @@ SubDir HAIKU_TOP src add-ons print transports usb_port ; 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 : diff --git a/src/add-ons/print/transports/usb_port/USBTransport.cpp b/src/add-ons/print/transports/usb_port/USBTransport.cpp index 338c256887..f57a8d9730 100644 --- a/src/add-ons/print/transports/usb_port/USBTransport.cpp +++ b/src/add-ons/print/transports/usb_port/USBTransport.cpp @@ -1,50 +1,68 @@ -/*****************************************************************************/ -// 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. -/*****************************************************************************/ - - -#include -#include -#include - -#include -#include - -#include +/* + * 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, + * Michael Pfeiffer, + * Andreas Benzler, + * Philippe Houdoin, + */ #include "PrintTransportAddOn.h" +#include +#include + +#include +#include + +#define PRINTER_INTERFACE_CLASS 0x07 +#define PRINTER_INTERFACE_SUBCLASS 0x01 + +// 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 PrinterMap; + PrinterMap fPrinters; +}; + class USBTransport : public BDataIO { @@ -52,16 +70,152 @@ 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 @@ instantiate_transport(BDirectory *printer, BMessage *msg) 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; } -