linux/drivers/nfc/port100.c
Thierry Escande 562d4d59b8 NFC: Sony Port-100 Series driver
This adds support for the Sony NFC USB dongle RC-S380, based on the
Port-100 chip. This dongle is an analog frontend and does not implement
the digital layer. This driver uses the nfc_digital module which is an
implementation of the NFC Digital Protocol stack.

This patch is a skeleton. It only registers the dongle against the NFC
digital protocol stack. All NFC digital operation functions are stubbed
out.

Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com>
Cc: Stephen Tiedemann <stephen.tiedemann@gmail.com>
Tested-by: Cho, Yu-Chen <acho@suse.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2013-10-07 14:09:33 +02:00

188 lines
4.6 KiB
C

/*
* Sony NFC Port-100 Series driver
* Copyright (c) 2013, Intel Corporation.
*
* Partly based/Inspired by Stephen Tiedemann's nfcpy
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/module.h>
#include <linux/usb.h>
#include <net/nfc/digital.h>
#define VERSION "0.1"
#define SONY_VENDOR_ID 0x054c
#define RCS380_PRODUCT_ID 0x06c1
#define PORT100_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
NFC_PROTO_MIFARE_MASK | \
NFC_PROTO_FELICA_MASK | \
NFC_PROTO_NFC_DEP_MASK)
#define PORT100_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \
NFC_DIGITAL_DRV_CAPS_TG_CRC)
struct port100 {
struct nfc_digital_dev *nfc_digital_dev;
int skb_headroom;
int skb_tailroom;
struct usb_device *udev;
struct usb_interface *interface;
};
static void port100_abort_cmd(struct nfc_digital_dev *ddev)
{
}
static int port100_switch_rf(struct nfc_digital_dev *ddev, bool on)
{
return -EOPNOTSUPP;
}
static int port100_in_configure_hw(struct nfc_digital_dev *ddev, int type,
int param)
{
return -EOPNOTSUPP;
}
static int port100_in_send_cmd(struct nfc_digital_dev *ddev,
struct sk_buff *skb, u16 _timeout,
nfc_digital_cmd_complete_t cb, void *arg)
{
return -EOPNOTSUPP;
}
static int port100_tg_configure_hw(struct nfc_digital_dev *ddev, int type,
int param)
{
return -EOPNOTSUPP;
}
static int port100_tg_send_cmd(struct nfc_digital_dev *ddev,
struct sk_buff *skb, u16 timeout,
nfc_digital_cmd_complete_t cb, void *arg)
{
return -EOPNOTSUPP;
}
static int port100_listen_mdaa(struct nfc_digital_dev *ddev,
struct digital_tg_mdaa_params *params,
u16 timeout,
nfc_digital_cmd_complete_t cb, void *arg)
{
return -EOPNOTSUPP;
}
static int port100_listen(struct nfc_digital_dev *ddev, u16 timeout,
nfc_digital_cmd_complete_t cb, void *arg)
{
return -EOPNOTSUPP;
}
static struct nfc_digital_ops port100_digital_ops = {
.in_configure_hw = port100_in_configure_hw,
.in_send_cmd = port100_in_send_cmd,
.tg_listen_mdaa = port100_listen_mdaa,
.tg_listen = port100_listen,
.tg_configure_hw = port100_tg_configure_hw,
.tg_send_cmd = port100_tg_send_cmd,
.switch_rf = port100_switch_rf,
.abort_cmd = port100_abort_cmd,
};
static const struct usb_device_id port100_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = SONY_VENDOR_ID,
.idProduct = RCS380_PRODUCT_ID,
},
{ }
};
MODULE_DEVICE_TABLE(usb, port100_table);
static int port100_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct port100 *dev;
int rc;
dev = devm_kzalloc(&interface->dev, sizeof(struct port100), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
usb_set_intfdata(interface, dev);
nfc_info(&interface->dev, "Sony NFC Port-100 Series attached\n");
dev->nfc_digital_dev = nfc_digital_allocate_device(&port100_digital_ops,
PORT100_PROTOCOLS,
PORT100_CAPABILITIES,
dev->skb_headroom,
dev->skb_tailroom);
if (!dev->nfc_digital_dev) {
nfc_err(&interface->dev,
"Could not allocate nfc_digital_dev.\n");
rc = -ENOMEM;
goto error;
}
nfc_digital_set_parent_dev(dev->nfc_digital_dev, &interface->dev);
nfc_digital_set_drvdata(dev->nfc_digital_dev, dev);
rc = nfc_digital_register_device(dev->nfc_digital_dev);
if (rc) {
nfc_err(&interface->dev,
"Could not register digital device.\n");
goto free_nfc_dev;
}
return 0;
free_nfc_dev:
nfc_digital_free_device(dev->nfc_digital_dev);
error:
return rc;
}
static void port100_disconnect(struct usb_interface *interface)
{
struct port100 *dev;
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
nfc_digital_unregister_device(dev->nfc_digital_dev);
nfc_digital_free_device(dev->nfc_digital_dev);
nfc_info(&interface->dev, "Sony Port-100 NFC device disconnected");
}
static struct usb_driver port100_driver = {
.name = "port100",
.probe = port100_probe,
.disconnect = port100_disconnect,
.id_table = port100_table,
};
module_usb_driver(port100_driver);
MODULE_DESCRIPTION("NFC Port-100 series usb driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");