* 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
This commit is contained in:
@@ -2,14 +2,14 @@ SubDir HAIKU_TOP src add-ons print transports usb_port ;
|
|||||||
|
|
||||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
|
|
||||||
UsePrivateHeaders print ;
|
UsePrivateHeaders shared print ;
|
||||||
|
|
||||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits print ] ;
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits print ] ;
|
||||||
|
|
||||||
Addon USB\ Port :
|
Addon USB\ Port :
|
||||||
USBTransport.cpp
|
USBTransport.cpp
|
||||||
PrintTransportAddOn.cpp
|
PrintTransportAddOn.cpp
|
||||||
: be $(TARGET_LIBSUPC++)
|
: libshared.a libdevice.so be $(TARGET_LIBSUPC++)
|
||||||
;
|
;
|
||||||
|
|
||||||
Package haiku-printingkit-cvs :
|
Package haiku-printingkit-cvs :
|
||||||
|
|||||||
@@ -1,50 +1,68 @@
|
|||||||
/*****************************************************************************/
|
/*
|
||||||
// USB port transport add-on,
|
* Copyright 2001-2010 Haiku Inc. All rights reserved.
|
||||||
// changes by Andreas Benzler, Philippe Houdoin
|
* Distributed under the terms of the MIT License.
|
||||||
//
|
*
|
||||||
// Original from Parallel
|
* Originally written based on Parallel port addon by Michael Pfeiffer,
|
||||||
// port transport add-on.
|
* changes by Andreas Benzler, Philippe Houdoin
|
||||||
//
|
* Rewritten to use the USBKit by Ithamar R. Adema.
|
||||||
// Author
|
* (Using code from usb_printer.cpp by Michael Lotz)
|
||||||
// Michael Pfeiffer
|
*
|
||||||
//
|
* Authors:
|
||||||
// This application and all source files used in its construction, except
|
* Ithamar R. Adema, <[email protected]>
|
||||||
// where noted, are licensed under the MIT License, and have been written
|
* Michael Pfeiffer,
|
||||||
// and are:
|
* Andreas Benzler,
|
||||||
//
|
* Philippe Houdoin,
|
||||||
// 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 <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <StorageKit.h>
|
|
||||||
#include <SupportKit.h>
|
|
||||||
|
|
||||||
#include <USB_printer.h>
|
|
||||||
|
|
||||||
#include "PrintTransportAddOn.h"
|
#include "PrintTransportAddOn.h"
|
||||||
|
|
||||||
|
#include <USBKit.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include <HashString.h>
|
||||||
|
#include <HashMap.h>
|
||||||
|
|
||||||
|
#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<HashString,USBPrinter*> PrinterMap;
|
||||||
|
PrinterMap fPrinters;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class USBTransport : public BDataIO
|
class USBTransport : public BDataIO
|
||||||
{
|
{
|
||||||
@@ -52,16 +70,152 @@ public:
|
|||||||
USBTransport(BDirectory *printer, BMessage *msg);
|
USBTransport(BDirectory *printer, BMessage *msg);
|
||||||
~USBTransport();
|
~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 Read(void *buffer, size_t size);
|
||||||
ssize_t Write(const void *buffer, size_t size);
|
ssize_t Write(const void *buffer, size_t size);
|
||||||
|
|
||||||
private:
|
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
|
// Implementation of transport add-on interface
|
||||||
|
|
||||||
BDataIO *
|
BDataIO *
|
||||||
@@ -75,99 +229,48 @@ instantiate_transport(BDirectory *printer, BMessage *msg)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List detected printers
|
||||||
status_t list_transport_ports(BMessage* msg)
|
status_t list_transport_ports(BMessage* msg)
|
||||||
{
|
{
|
||||||
BDirectory dir("/dev/printer/usb");
|
return gUSBPrinterRoster.ListPrinters(msg);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Implementation of USBTransport
|
// Implementation of USBTransport
|
||||||
|
|
||||||
USBTransport::USBTransport(BDirectory *printer, BMessage *msg)
|
USBTransport::USBTransport(BDirectory *printer, BMessage *msg)
|
||||||
: fFile(-1)
|
: fPrinter(NULL)
|
||||||
{
|
{
|
||||||
char device_id[USB_PRINTER_DEVICE_ID_LENGTH + 1];
|
BString key;
|
||||||
char name[USB_PRINTER_DEVICE_ID_LENGTH + 1];
|
|
||||||
char *desc;
|
if (printer->ReadAttrString("transport_address", &key) < 0)
|
||||||
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)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Get printer's DEVICE ID string
|
fPrinter = gUSBPrinterRoster.Printer(key.String());
|
||||||
ret = ioctl(fFile, USB_PRINTER_GET_DEVICE_ID, device_id, sizeof(device_id));
|
if (!fPrinter)
|
||||||
if (ret < 0) {
|
|
||||||
close(fFile);
|
|
||||||
fFile = -1;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
// If caller doesn't care...
|
||||||
if (! msg)
|
if (!msg)
|
||||||
// Caller don't care about transport init message output content...
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Fill up the message
|
// Fill up the message
|
||||||
msg->what = 'okok';
|
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()
|
USBTransport::~USBTransport()
|
||||||
{
|
{
|
||||||
if (fFile > -1)
|
|
||||||
close(fFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
USBTransport::Read(void *buffer, size_t size)
|
USBTransport::Read(void *buffer, size_t size)
|
||||||
{
|
{
|
||||||
return read(fFile, buffer, size);
|
return fPrinter ? fPrinter->Read(buffer, size) : B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
USBTransport::Write(const void *buffer, size_t size)
|
USBTransport::Write(const void *buffer, size_t size)
|
||||||
{
|
{
|
||||||
return write(fFile, buffer, size);
|
return fPrinter ? fPrinter->Write(buffer, size) : B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user